1
0
Fork 0
mirror of https://github.com/betaflight/betaflight-configurator.git synced 2025-07-20 23:05:15 +03:00

Merge branch 'master' into rc_smoothing

This commit is contained in:
Sean M 2018-08-11 20:59:00 -04:00
commit f4ea605685
45 changed files with 18196 additions and 463 deletions

156
src/js/Analytics.js Normal file
View file

@ -0,0 +1,156 @@
'use strict';
var Analytics = function (trackingId, userId, appName, appVersion, buildType, optOut, debugMode) {
this._trackingId = trackingId;
this.setOptOut(optOut);
this._googleAnalytics = googleAnalytics;
this._googleAnalytics.initialize(this._trackingId, {
storage: 'none',
clientId: userId,
debug: !!debugMode
});
// Make it work for the Chrome App:
this._googleAnalytics.set('forceSSL', true);
this._googleAnalytics.set('transport', 'xhr');
// Make it work for NW.js:
this._googleAnalytics.set('checkProtocolTask', null);
this._googleAnalytics.set('appName', appName);
this._googleAnalytics.set('appVersion', debugMode ? appVersion + '-debug' : appVersion);
this.EVENT_CATEGORIES = {
APPLICATION: 'Application',
FLIGHT_CONTROLLER: 'FlightController',
FIRMWARE: 'Firmware',
};
this.DATA = {
BOARD_TYPE: 'boardType',
API_VERSION: 'apiVersion',
FIRMWARE_TYPE: 'firmwareType',
FIRMWARE_VERSION: 'firmwareVersion',
FIRMWARE_NAME: 'firmwareName',
FIRMWARE_CHECKSUM: 'firmwareChecksum',
FIRMWARE_SOURCE: 'firmwareSource',
FIRMWARE_CHANNEL: 'firmwareChannel',
FIRMWARE_ERASE_ALL: 'firmwareEraseAll',
FIRMWARE_SIZE: 'firmwareSize',
MCU_ID: 'mcuId',
LOGGING_STATUS: 'loggingStatus',
LOG_SIZE: 'logSize',
};
this.DIMENSIONS = {
CONFIGURATOR_BUILD_TYPE: 1,
BOARD_TYPE: 2,
FIRMWARE_TYPE: 3,
FIRMWARE_VERSION: 4,
API_VERSION: 5,
FIRMWARE_NAME: 6,
FIRMWARE_SOURCE: 7,
FIRMWARE_ERASE_ALL: 8,
CONFIGURATOR_EXPERT_MODE: 9,
FIRMWARE_CHANNEL: 10,
LOGGING_STATUS: 11,
MCU_ID: 12,
};
this.METRICS = {
FIRMWARE_SIZE: 1,
LOG_SIZE: 2,
};
this.setDimension(this.DIMENSIONS.CONFIGURATOR_BUILD_TYPE, buildType);
this.resetFlightControllerData();
this.resetFirmwareData();
};
Analytics.prototype.setDimension = function (dimension, value) {
var dimensionName = 'dimension' + dimension;
this._googleAnalytics.custom(dimensionName, value);
}
Analytics.prototype.setMetric = function (metric, value) {
var metricName = 'metric' + metric;
this._googleAnalytics.custom(metricName, value);
}
Analytics.prototype.sendEvent = function (category, action, options) {
this._googleAnalytics.event(category, action, options);
}
Analytics.prototype.sendChangeEvents = function (category, changeList) {
for (var actionName in changeList) {
if (changeList.hasOwnProperty(actionName)) {
var actionValue = changeList[actionName];
if (actionValue !== undefined) {
this.sendEvent(category, actionName, { eventLabel: actionValue });
}
}
}
}
Analytics.prototype.sendAppView = function (viewName) {
this._googleAnalytics.screenview(viewName);
}
Analytics.prototype.sendTiming = function (category, timing, value) {
this._googleAnalytics.timing(category, timing, value);
}
Analytics.prototype.sendException = function (message) {
this._googleAnalytics.exception(message);
}
Analytics.prototype.setOptOut = function (optOut) {
window['ga-disable-' + this._trackingId] = !!optOut;
}
Analytics.prototype._rebuildFlightControllerEvent = function () {
this.setDimension(this.DIMENSIONS.BOARD_TYPE, this._flightControllerData[this.DATA.BOARD_TYPE]);
this.setDimension(this.DIMENSIONS.FIRMWARE_TYPE, this._flightControllerData[this.DATA.FIRMWARE_TYPE]);
this.setDimension(this.DIMENSIONS.FIRMWARE_VERSION, this._flightControllerData[this.DATA.FIRMWARE_VERSION]);
this.setDimension(this.DIMENSIONS.API_VERSION, this._flightControllerData[this.DATA.API_VERSION]);
this.setDimension(this.DIMENSIONS.LOGGING_STATUS, this._flightControllerData[this.DATA.LOGGING_STATUS]);
this.setDimension(this.DIMENSIONS.MCU_ID, this._flightControllerData[this.DATA.MCU_ID]);
this.setMetric(this.METRICS.LOG_SIZE, this._flightControllerData[this.DATA.LOG_SIZE]);
}
Analytics.prototype.setFlightControllerData = function (property, value) {
this._flightControllerData[property] = value;
this._rebuildFlightControllerEvent();
}
Analytics.prototype.resetFlightControllerData = function () {
this._flightControllerData = {};
this._rebuildFlightControllerEvent();
}
Analytics.prototype._rebuildFirmwareEvent = function () {
this.setDimension(this.DIMENSIONS.FIRMWARE_NAME, this._firmwareData[this.DATA.FIRMWARE_NAME]);
this.setDimension(this.DIMENSIONS.FIRMWARE_SOURCE, this._firmwareData[this.DATA.FIRMWARE_SOURCE]);
this.setDimension(this.DIMENSIONS.FIRMWARE_ERASE_ALL, this._firmwareData[this.DATA.FIRMWARE_ERASE_ALL]);
this.setDimension(this.DIMENSIONS.FIRMWARE_CHANNEL, this._firmwareData[this.DATA.FIRMWARE_CHANNEL]);
this.setMetric(this.METRICS.FIRMWARE_SIZE, this._firmwareData[this.DATA.FIRMWARE_SIZE]);
this._googleAnalytics.set('eventLabel', this._firmwareData[this.DATA.FIRMWARE_CHECKSUM]);
}
Analytics.prototype.setFirmwareData = function (property, value) {
this._firmwareData[property] = value;
this._rebuildFirmwareEvent();
}
Analytics.prototype.resetFirmwareData = function () {
this._firmwareData = {};
this._rebuildFirmwareEvent();
}

View file

@ -99,11 +99,16 @@ var Features = function (config) {
self._features = features;
self._featureMask = 0;
self._analyticsChanges = {};
};
Features.prototype.getMask = function () {
var self = this;
analytics.sendChangeEvents(analytics.EVENT_CATEGORIES.FLIGHT_CONTROLLER, self._analyticsChanges);
self._analyticsChanges = {};
return self._featureMask;
};
@ -127,6 +132,8 @@ Features.prototype.isEnabled = function (featureName) {
Features.prototype.generateElements = function (featuresElements) {
var self = this;
self._featureChanges = {};
var listElements = [];
for (var i = 0; i < self._features.length; i++) {
@ -191,29 +198,48 @@ Features.prototype.generateElements = function (featuresElements) {
}
};
Features.prototype.findFeatureByBit = function (bit) {
var self = this;
for (var i = 0; i < self._features.length; i++) {
if (self._features[i].bit == bit) {
return self._features[i];
}
}
}
Features.prototype.updateData = function (featureElement) {
var self = this;
if (featureElement.attr('type') === 'checkbox') {
var bit = featureElement.data('bit');
var featureValue;
if (featureElement.is(':checked')) {
self._featureMask = bit_set(self._featureMask, bit);
featureValue = 'On';
} else {
self._featureMask = bit_clear(self._featureMask, bit);
featureValue = 'Off';
}
self._analyticsChanges['Feature' + self.findFeatureByBit(bit).name] = featureValue;
} else if (featureElement.prop('localName') === 'select') {
var controlElements = featureElement.children();
var selectedBit = featureElement.val();
if (selectedBit !== -1) {
var selectedFeature;
for (var i = 0; i < controlElements.length; i++) {
var bit = controlElements[i].value;
if (selectedBit === bit) {
self._featureMask = bit_set(self._featureMask, bit);
selectedFeature = self.findFeatureByBit(bit);
} else {
self._featureMask = bit_clear(self._featureMask, bit);
}
}
if (selectedFeature) {
self._analyticsChanges['FeatureGroup-' + selectedFeature.group] = selectedFeature.name;
}
}
}
};

View file

@ -26,7 +26,7 @@ var LogoManager = LogoManager || {
},
// config for logo image selection dialog
acceptFileTypes: [
{ extensions: ['png', 'bmp'] },
{ description: 'images', extensions: ['png', 'bmp'] },
],
};

View file

@ -141,6 +141,11 @@ function configuration_backup(callback) {
configuration.SERIAL_CONFIG = jQuery.extend(true, {}, SERIAL_CONFIG);
configuration.LED_STRIP = jQuery.extend(true, [], LED_STRIP);
configuration.LED_COLORS = jQuery.extend(true, [], LED_COLORS);
configuration.BOARD_ALIGNMENT_CONFIG = jQuery.extend(true, {}, BOARD_ALIGNMENT_CONFIG);
configuration.CRAFT_NAME = CONFIG.name;
configuration.MIXER_CONFIG = jQuery.extend(true, {}, MIXER_CONFIG);
configuration.SENSOR_CONFIG = jQuery.extend(true, {}, SENSOR_CONFIG);
configuration.PID_ADVANCED_CONFIG = jQuery.extend(true, {}, PID_ADVANCED_CONFIG);
if (semver.gte(CONFIG.apiVersion, "1.19.0")) {
configuration.LED_MODE_COLORS = jQuery.extend(true, [], LED_MODE_COLORS);
@ -165,13 +170,31 @@ function configuration_backup(callback) {
configuration.GPS_CONFIG = jQuery.extend(true, {}, GPS_CONFIG);
configuration.COMPASS_CONFIG = jQuery.extend(true, {}, COMPASS_CONFIG);
}
if (semver.gte(CONFIG.apiVersion, "1.36.0")) {
configuration.BEEPER_CONFIG = jQuery.extend(true, {}, BEEPER_CONFIG);
}
save();
}
}
// start fetching
fetch_unique_data_item();
if (GUI.configuration_loaded === true) {
return fetch_unique_data_item();
}
MSP.promise(MSPCodes.MSP_ADVANCED_CONFIG).then(function() {
return MSP.promise(MSPCodes.MSP_SENSOR_CONFIG);
}).then(function() {
return MSP.promise(MSPCodes.MSP_NAME);
}).then(function() {
return MSP.promise(MSPCodes.MSP_BOARD_ALIGNMENT_CONFIG);
}).then(function() {
return MSP.promise(MSPCodes.MSP_MIXER_CONFIG);
}).then(function() {
return MSP.promise(MSPCodes.MSP_BEEPER_CONFIG);
}).then(function() {
return fetch_unique_data_item();
});
}
function save() {
@ -183,7 +206,7 @@ function configuration_backup(callback) {
var filename = generateFilename(prefix, suffix);
var accepts = [{
extensions: [suffix]
description: suffix.toUpperCase() + ' files', extensions: [suffix]
}];
// create or load the file
@ -231,6 +254,7 @@ function configuration_backup(callback) {
return;
}
analytics.sendEvent(analytics.EVENT_CATEGORIES.FLIGHT_CONTROLLER, 'Backup');
console.log('Write SUCCESSFUL');
if (callback) callback();
};
@ -254,7 +278,7 @@ function configuration_restore(callback) {
var chosenFileEntry = null;
var accepts = [{
extensions: ['json']
description: 'JSON files', extensions: ['json']
}];
// load up the file
@ -303,26 +327,23 @@ function configuration_restore(callback) {
// validate
if (typeof configuration.generatedBy !== 'undefined' && compareVersions(configuration.generatedBy, CONFIGURATOR.backupFileMinVersionAccepted)) {
if (typeof configuration.generatedBy !== 'undefined' && compareVersions(configuration.generatedBy, CONFIGURATOR.backupFileMinVersionAccepted)) {
if (!compareVersions(configuration.generatedBy, "1.14.0") && !migrate(configuration)) {
GUI.log(i18n.getMessage('backupFileUnmigratable'));
return;
}
if (configuration.FEATURE_CONFIG.features._featureMask) {
var features = new Features(CONFIG);
features.setMask(configuration.FEATURE_CONFIG.features._featureMask);
configuration.FEATURE_CONFIG.features = features;
}
analytics.sendEvent(analytics.EVENT_CATEGORIES.FLIGHT_CONTROLLER, 'Restore');
configuration_upload(configuration, callback);
} else {
GUI.log(i18n.getMessage('backupFileIncompatible'));
}
}
};
@ -763,6 +784,13 @@ function configuration_restore(callback) {
];
function update_unique_data_list() {
uniqueData.push(MSPCodes.MSP_SET_NAME);
uniqueData.push(MSPCodes.MSP_SET_SENSOR_CONFIG);
uniqueData.push(MSPCodes.MSP_SET_MIXER_CONFIG);
uniqueData.push(MSPCodes.MSP_SET_BEEPER_CONFIG);
uniqueData.push(MSPCodes.MSP_SET_BOARD_ALIGNMENT_CONFIG);
uniqueData.push(MSPCodes.MSP_SET_ADVANCED_CONFIG);
if (semver.gte(CONFIG.apiVersion, "1.8.0")) {
uniqueData.push(MSPCodes.MSP_SET_LOOP_TIME);
uniqueData.push(MSPCodes.MSP_SET_ARMING_CONFIG);
@ -803,6 +831,17 @@ function configuration_restore(callback) {
GPS_CONFIG = configuration.GPS_CONFIG;
COMPASS_CONFIG = configuration.COMPASS_CONFIG;
RSSI_CONFIG = configuration.RSSI_CONFIG;
BOARD_ALIGNMENT_CONFIG = configuration.BOARD_ALIGNMENT_CONFIG;
CONFIG.name = configuration.CRAFT_NAME;
MIXER_CONFIG = configuration.MIXER_CONFIG;
SENSOR_CONFIG = configuration.SENSOR_CONFIG;
PID_ADVANCED_CONFIG = configuration.PID_ADVANCED_CONFIG;
BEEPER_CONFIG.beepers = new Beepers(CONFIG);
BEEPER_CONFIG.beepers.setMask(configuration.BEEPER_CONFIG.beepers._beeperMask);
BEEPER_CONFIG.dshotBeaconTone = configuration.BEEPER_CONFIG.dshotBeaconTone;
BEEPER_CONFIG.dshotBeaconConditions = new Beepers(CONFIG, [ "RX_LOST", "RX_SET" ]);
BEEPER_CONFIG.dshotBeaconConditions.setMask(configuration.BEEPER_CONFIG.dshotBeaconConditions._beeperMask);
}
function send_unique_data_item() {

View file

@ -369,6 +369,18 @@ var FC = {
levelSensitivity: 0,
itermThrottleThreshold: 0,
itermAcceleratorGain: 0,
itermRotation: 0,
smartFeedforward: 0,
itermRelax: 0,
itermRelaxType: 0,
absoluteControlGain: 0,
throttleBoost: 0,
acroTrainerAngleLimit: 0,
feedforwardRoll: 0,
feedforwardPitch: 0,
feedforwardYaw: 0,
feedforwardTransition: 0,
antiGravityMode: 0,
};
SENSOR_CONFIG = {

View file

@ -321,5 +321,17 @@ GUI_control.prototype.content_ready = function (callback) {
if (callback) callback();
}
GUI_control.prototype.selectDefaultTabWhenConnected = function() {
chrome.storage.local.get(['rememberLastTab', 'lastTab'], function (result) {
if (!(result.rememberLastTab
&& !!result.lastTab
&& result.lastTab.substring(4) != "cli")) {
$('#tabs ul.mode-connected .tab_setup a').click();
return;
}
$("#tabs ul.mode-connected ." + result.lastTab + " a").click();
});
};
// initialize object into GUI variable
var GUI = new GUI_control();

View file

@ -1,66 +1,124 @@
'use strict;'
var JenkinsLoader = function (url, jobName) {
var self = this;
self._url = url;
self._jobName = jobName;
self._jobUrl = self._url + '/job/' + self._jobName;
self._buildsRequest = '/api/json?tree=builds[number,result,timestamp,artifacts[relativePath],changeSet[items[commitId,msg]]]';
self._builds = {};
var JenkinsLoader = function (url) {
this._url = url;
this._jobs = [];
this._cacheExpirationPeriod = 3600 * 1000;
self._buildsDataTag = `${self._jobUrl}BuildsData`;
self._cacheLastUpdateTag = `${self._jobUrl}BuildsLastUpdate`
this._jobsRequest = '/api/json?tree=jobs[name]';
this._buildsRequest = '/api/json?tree=builds[number,result,timestamp,artifacts[relativePath],changeSet[items[commitId,msg]]]';
}
JenkinsLoader.prototype.loadBuilds = function (callback) {
JenkinsLoader.prototype.loadJobs = function (viewName, callback) {
var self = this;
chrome.storage.local.get([self._cacheLastUpdateTag, self._buildsDataTag], function (result) {
var buildsDataTimestamp = $.now();
var cachedBuildsData = result[self._buildsDataTag];
var cachedBuildsLastUpdate = result[self._cacheLastUpdateTag];
var viewUrl = `${self._url}/view/${viewName}`;
var jobsDataTag = '${viewUrl}JobsData';
var cacheLastUpdateTag = '${viewUrl}JobsLastUpdate';
if (!cachedBuildsData || !cachedBuildsLastUpdate || buildsDataTimestamp - cachedBuildsLastUpdate > 3600 * 1000) {
var request = self._jobUrl + self._buildsRequest;
var wrappedCallback = jobs => {
self._jobs = jobs;
callback(jobs);
};
$.get(request, function (buildsInfo) {
// filter successful builds
self._builds = buildsInfo.builds.filter(build => build.result == 'SUCCESS')
.map(build => ({
number: build.number,
artifacts: build.artifacts.map(artifact => artifact.relativePath),
changes: build.changeSet.items.map(item => '* ' + item.msg).join('<br>\n'),
date: new Date(build.timestamp)
}));
chrome.storage.local.get([cacheLastUpdateTag, jobsDataTag], function (result) {
var jobsDataTimestamp = $.now();
var cachedJobsData = result[jobsDataTag];
var cachedJobsLastUpdate = result[cacheLastUpdateTag];
self._parseBuilds(callback);
}).fail(function (data) {
GUI.log(i18n.getMessage('releaseCheckFailed', [self._jobName, 'failed to load builds']));
self._builds = cachedBuildsData;
self._parseBuilds(callback);
});
} else {
if (cachedBuildsData) {
GUI.log(i18n.getMessage('releaseCheckCached', [self._jobName]));
var cachedCallback = () => {
if (cachedJobsData) {
GUI.log(i18n.getMessage('buildServerUsingCached', ['jobs']));
}
self._builds = cachedBuildsData;
self._parseBuilds(callback);
wrappedCallback(cachedJobsData ? cachedJobsData : []);
};
if (!cachedJobsData || !cachedJobsLastUpdate || jobsDataTimestamp - cachedJobsLastUpdate > self._cacheExpirationPeriod) {
var url = `${viewUrl}${self._jobsRequest}`;
$.get(url, jobsInfo => {
GUI.log(i18n.getMessage('buildServerLoaded', ['jobs']));
// remove Betaflight prefix, rename Betaflight job to Development
var jobs = jobsInfo.jobs.map(job => {
return { title: job.name.replace('Betaflight ', '').replace('Betaflight', 'Development'), name: job.name };
})
// cache loaded info
object = {}
object[jobsDataTag] = jobs;
object[cacheLastUpdateTag] = $.now();
chrome.storage.local.set(object);
wrappedCallback(jobs);
}).error(xhr => {
GUI.log(i18n.getMessage('buildServerLoadFailed', ['jobs', `HTTP ${xhr.status}`]));
}).fail(cachedCallback);
} else {
cachedCallback();
}
});
}
JenkinsLoader.prototype._parseBuilds = function (callback) {
JenkinsLoader.prototype.loadBuilds = function (jobName, callback) {
var self = this;
var jobUrl = `${self._url}/job/${jobName}`;
var buildsDataTag = `${jobUrl}BuildsData`;
var cacheLastUpdateTag = `${jobUrl}BuildsLastUpdate`
chrome.storage.local.get([cacheLastUpdateTag, buildsDataTag], function (result) {
var buildsDataTimestamp = $.now();
var cachedBuildsData = result[buildsDataTag];
var cachedBuildsLastUpdate = result[cacheLastUpdateTag];
var cachedCallback = () => {
if (cachedBuildsData) {
GUI.log(i18n.getMessage('buildServerUsingCached', [jobName]));
}
self._parseBuilds(jobUrl, jobName, cachedBuildsData ? cachedBuildsData : [], callback);
};
if (!cachedBuildsData || !cachedBuildsLastUpdate || buildsDataTimestamp - cachedBuildsLastUpdate > self._cacheExpirationPeriod) {
var url = `${jobUrl}${self._buildsRequest}`;
$.get(url, function (buildsInfo) {
GUI.log(i18n.getMessage('buildServerLoaded', [jobName]));
// filter successful builds
var builds = buildsInfo.builds.filter(build => build.result == 'SUCCESS')
.map(build => ({
number: build.number,
artifacts: build.artifacts.map(artifact => artifact.relativePath),
changes: build.changeSet.items.map(item => '* ' + item.msg).join('<br>\n'),
timestamp: build.timestamp
}));
// cache loaded info
object = {}
object[buildsDataTag] = builds;
object[cacheLastUpdateTag] = $.now();
chrome.storage.local.set(object);
self._parseBuilds(jobUrl, jobName, builds, callback);
}).error(xhr => {
GUI.log(i18n.getMessage('buildServerLoadFailed', [jobName, `HTTP ${xhr.status}`]));
}).fail(cachedCallback);
} else {
cachedCallback();
}
});
}
JenkinsLoader.prototype._parseBuilds = function (jobUrl, jobName, builds, callback) {
// convert from `build -> targets` to `target -> builds` mapping
var targetBuilds = {};
var targetFromFilenameExpression = /betaflight_([\d.]+)?_?(\w+)(\-.*)?\.(.*)/;
self._builds.forEach(build => {
builds.forEach(build => {
build.artifacts.forEach(relativePath => {
var match = targetFromFilenameExpression.exec(relativePath);
@ -70,15 +128,16 @@ JenkinsLoader.prototype._parseBuilds = function (callback) {
var version = match[1];
var target = match[2];
var date = new Date(build.timestamp);
var formattedDate = ("0" + build.date.getDate()).slice(-2) + "-" + ("0" + (build.date.getMonth()+1)).slice(-2) + "-" +
build.date.getFullYear() + " " + ("0" + build.date.getHours()).slice(-2) + ":" + ("0" + build.date.getMinutes()).slice(-2);
var formattedDate = ("0" + date.getDate()).slice(-2) + "-" + ("0" + (date.getMonth()+1)).slice(-2) + "-" +
date.getFullYear() + " " + ("0" + date.getHours()).slice(-2) + ":" + ("0" + date.getMinutes()).slice(-2);
var descriptor = {
'releaseUrl': self._jobUrl + '/' + build.number,
'name' : self._jobName + ' #' + build.number,
'releaseUrl': jobUrl + '/' + build.number,
'name' : jobName + ' #' + build.number,
'version' : version + ' #' + build.number,
'url' : self._jobUrl + '/' + build.number + '/artifact/' + relativePath,
'url' : jobUrl + '/' + build.number + '/artifact/' + relativePath,
'file' : relativePath.split('/').slice(-1)[0],
'target' : target,
'date' : formattedDate,

View file

@ -1,9 +1,10 @@
'use strict';
var googleAnalytics = analytics;
var analytics = undefined;
openNewWindowsInExternalBrowser();
//Asynchronous configuration to be done.
//When finish the startProcess() function must be called
$(document).ready(function () {
i18n.init(function() {
startProcess();
@ -11,9 +12,67 @@ $(document).ready(function () {
});
});
function checkSetupAnalytics(callback) {
if (!analytics) {
setTimeout(function () {
chrome.storage.local.get(['userId', 'analyticsOptOut'], function (result) {
if (!analytics) {
setupAnalytics(result);
}
callback(analytics);
});
});
} else if (callback) {
callback(analytics);
}
};
function setupAnalytics(result) {
var userId;
if (result.userId) {
userId = result.userId;
} else {
var uid = new ShortUniqueId();
userId = uid.randomUUID(13);
chrome.storage.local.set({ 'userId': userId });
}
var optOut = !!result.analyticsOptOut;
var debugMode = process.versions['nw-flavor'] === 'sdk';
analytics = new Analytics('UA-123002063-1', userId, 'Betaflight Configurator', getManifestVersion(), GUI.operating_system, optOut, debugMode);
function logException(exception) {
analytics.sendException(exception.stack);
}
process.on('uncaughtException', logException);
analytics.sendEvent(analytics.EVENT_CATEGORIES.APPLICATION, 'AppStart', { sessionControl: 'start' });
function sendCloseEvent() {
analytics.sendEvent(analytics.EVENT_CATEGORIES.APPLICATION, 'AppClose', { sessionControl: 'end' })
}
try {
var gui = require('nw.gui');
var win = gui.Window.get();
win.on('close', function () {
sendCloseEvent();
this.close(true);
});
} catch (ex) {
// Looks like we're in Chrome - but the event does not actually get fired
chrome.runtime.onSuspend.addListener(sendCloseEvent);
}
}
//Process to execute to real start the app
function startProcess() {
// translate to user-selected language
i18n.localizePage();
@ -86,6 +145,13 @@ function startProcess() {
return;
}
$("#tabs ul.mode-connected li").click(function() {
// store the first class of the current tab (omit things like ".active")
chrome.storage.local.set({
lastTab: $(this).attr("class").split(' ')[0]
});
});
GUI.tab_switch_in_progress = true;
GUI.tab_switch_cleanup(function () {
@ -106,6 +172,10 @@ function startProcess() {
GUI.tab_switch_in_progress = false;
}
checkSetupAnalytics(function (analytics) {
analytics.sendAppView(tab);
});
switch (tab) {
case 'landing':
TABS.landing.initialize(content_ready);
@ -210,13 +280,16 @@ function startProcess() {
chrome.storage.local.set({'permanentExpertMode': checked});
$('input[name="expertModeCheckbox"]').prop('checked', checked).change();
if (FEATURE_CONFIG) {
updateTabList(FEATURE_CONFIG.features);
}
}).change();
});
chrome.storage.local.get('rememberLastTab', function (result) {
$('div.rememberLastTab input')
.prop('checked', !!result.rememberLastTab)
.change(function() { chrome.storage.local.set({rememberLastTab: $(this).is(':checked')}) })
.change();
});
if (GUI.operating_system !== 'ChromeOS') {
chrome.storage.local.get('checkForConfiguratorUnstableVersions', function (result) {
if (result.checkForConfiguratorUnstableVersions) {
@ -235,6 +308,30 @@ function startProcess() {
$('div.checkForConfiguratorUnstableVersions').hide();
}
chrome.storage.local.get('analyticsOptOut', function (result) {
if (result.analyticsOptOut) {
$('div.analyticsOptOut input').prop('checked', true);
}
$('div.analyticsOptOut input').change(function () {
var checked = $(this).is(':checked');
chrome.storage.local.set({'analyticsOptOut': checked});
checkSetupAnalytics(function (analytics) {
if (checked) {
analytics.sendEvent(analytics.EVENT_CATEGORIES.APPLICATION, 'OptOut');
}
analytics.setOptOut(checked);
if (!checked) {
analytics.sendEvent(analytics.EVENT_CATEGORIES.APPLICATION, 'OptIn');
}
});
}).change();
});
chrome.storage.local.get('userLanguageSelect', function (result) {
var userLanguage_e = $('div.userLanguage select');
@ -385,6 +482,11 @@ function startProcess() {
}
$('input[name="expertModeCheckbox"]').change(function () {
var checked = $(this).is(':checked');
checkSetupAnalytics(function (analytics) {
analytics.setDimension(analytics.DIMENSIONS.CONFIGURATOR_EXPERT_MODE, checked ? 'On' : 'Off');
});
if (FEATURE_CONFIG) {
updateTabList(FEATURE_CONFIG.features);
}
@ -642,4 +744,16 @@ function openNewWindowsInExternalBrowser() {
} catch (ex) {
console.log("require does not exist, maybe inside chrome");
}
}
}
function showErrorDialog(message) {
var dialog = $('.dialogError')[0];
$('.dialogError-content').html(message);
$('.dialogError-closebtn').click(function() {
dialog.close();
});
dialog.showModal();
}

View file

@ -27,6 +27,12 @@ function MspHelper () {
'RUNCAM_DEVICE_CONTROL': 14, // support communitate with RunCam Device
'LIDAR_TF': 15
};
self.REBOOT_TYPES = {
FIRMWARE: 0,
BOOTLOADER: 1,
MSC: 2
};
}
MspHelper.prototype.reorderPwmProtocols = function (protocol) {
@ -617,6 +623,17 @@ MspHelper.prototype.process_data = function(dataHandler) {
break;
case MSPCodes.MSP_SET_REBOOT:
if (semver.gte(CONFIG.apiVersion, "1.40.0")) {
var rebootType = data.read8();
if (rebootType === self.REBOOT_TYPES.MSC) {
if (data.read8() === 0) {
console.log('Storage device not ready.');
showErrorDialog(i18n.getMessage('storageDeviceNotReady'));
break;
}
}
}
console.log('Reboot request accepted');
break;
@ -871,7 +888,11 @@ MspHelper.prototype.process_data = function(dataHandler) {
ADVANCED_TUNING.deltaMethod = data.readU8();
ADVANCED_TUNING.vbatPidCompensation = data.readU8();
if (semver.gte(CONFIG.apiVersion, "1.20.0")) {
ADVANCED_TUNING.dtermSetpointTransition = data.readU8();
if (semver.gte(CONFIG.apiVersion, "1.40.0")) {
ADVANCED_TUNING.feedforwardTransition = data.readU8();
} else {
ADVANCED_TUNING.dtermSetpointTransition = data.readU8();
}
ADVANCED_TUNING.dtermSetpointWeight = data.readU8();
ADVANCED_TUNING.toleranceBand = data.readU8();
ADVANCED_TUNING.toleranceBandReduction = data.readU8();
@ -881,13 +902,29 @@ MspHelper.prototype.process_data = function(dataHandler) {
if (semver.gte(CONFIG.apiVersion, "1.24.0")) {
ADVANCED_TUNING.levelAngleLimit = data.readU8();
ADVANCED_TUNING.levelSensitivity = data.readU8();
}
if (semver.gte(CONFIG.apiVersion, "1.36.0")) {
ADVANCED_TUNING.itermThrottleThreshold = data.readU16();
ADVANCED_TUNING.itermAcceleratorGain = data.readU16();
}
if (semver.gte(CONFIG.apiVersion, "1.39.0")) {
ADVANCED_TUNING.dtermSetpointWeight = data.readU16();
if (semver.gte(CONFIG.apiVersion, "1.36.0")) {
ADVANCED_TUNING.itermThrottleThreshold = data.readU16();
ADVANCED_TUNING.itermAcceleratorGain = data.readU16();
if (semver.gte(CONFIG.apiVersion, "1.39.0")) {
ADVANCED_TUNING.dtermSetpointWeight = data.readU16();
if (semver.gte(CONFIG.apiVersion, "1.40.0")) {
ADVANCED_TUNING.itermRotation = data.readU8();
ADVANCED_TUNING.smartFeedforward = data.readU8();
ADVANCED_TUNING.itermRelax = data.readU8();
ADVANCED_TUNING.itermRelaxType = data.readU8();
ADVANCED_TUNING.absoluteControlGain = data.readU8();
ADVANCED_TUNING.throttleBoost = data.readU8();
ADVANCED_TUNING.acroTrainerAngleLimit = data.readU8();
ADVANCED_TUNING.feedforwardRoll = data.readU16();
ADVANCED_TUNING.feedforwardPitch = data.readU16();
ADVANCED_TUNING.feedforwardYaw = data.readU16();
ADVANCED_TUNING.antiGravityMode = data.readU8();
}
}
}
}
}
break;
@ -1119,7 +1156,9 @@ MspHelper.prototype.process_data = function(dataHandler) {
case MSPCodes.MSP_SET_ADJUSTMENT_RANGE:
console.log('Adjustment range saved');
break;
case MSPCodes.MSP_SET_BOARD_ALIGNMENT_CONFIG:
console.log('Board alignment saved');
break;
case MSPCodes.MSP_PID_CONTROLLER:
PID.controller = data.readU8();
break;
@ -1195,6 +1234,11 @@ MspHelper.prototype.process_data = function(dataHandler) {
console.log('Unknown code detected: ' + code);
} else {
console.log('FC reports unsupported message error: ' + code);
switch (code) {
case MSPCodes.MSP_SET_REBOOT:
showErrorDialog(i18n.getMessage('operationNotSupported'));
}
}
}
// trigger callbacks, cleanup/remove callback after trigger
@ -1217,7 +1261,6 @@ MspHelper.prototype.process_data = function(dataHandler) {
}
}
/**
* Encode the request body for the MSP request with the given code and return it as an array of bytes.
*/
@ -1526,24 +1569,47 @@ MspHelper.prototype.crunch = function(code) {
.push16(ADVANCED_TUNING.yawItermIgnoreRate)
.push16(ADVANCED_TUNING.yaw_p_limit)
.push8(ADVANCED_TUNING.deltaMethod)
.push8(ADVANCED_TUNING.vbatPidCompensation)
.push8(ADVANCED_TUNING.dtermSetpointTransition)
.push8(Math.min(ADVANCED_TUNING.dtermSetpointWeight, 254))
.push8(ADVANCED_TUNING.toleranceBand)
.push8(ADVANCED_TUNING.toleranceBandReduction)
.push8(ADVANCED_TUNING.itermThrottleGain)
.push16(ADVANCED_TUNING.pidMaxVelocity)
.push16(ADVANCED_TUNING.pidMaxVelocityYaw);
.push8(ADVANCED_TUNING.vbatPidCompensation);
if (semver.gte(CONFIG.apiVersion, "1.40.0")) {
buffer.push8(ADVANCED_TUNING.feedforwardTransition);
} else {
buffer.push8(ADVANCED_TUNING.dtermSetpointTransition);
}
buffer.push8(Math.min(ADVANCED_TUNING.dtermSetpointWeight, 254))
.push8(ADVANCED_TUNING.toleranceBand)
.push8(ADVANCED_TUNING.toleranceBandReduction)
.push8(ADVANCED_TUNING.itermThrottleGain)
.push16(ADVANCED_TUNING.pidMaxVelocity)
.push16(ADVANCED_TUNING.pidMaxVelocityYaw);
if (semver.gte(CONFIG.apiVersion, "1.24.0")) {
buffer.push8(ADVANCED_TUNING.levelAngleLimit)
.push8(ADVANCED_TUNING.levelSensitivity);
}
if (semver.gte(CONFIG.apiVersion, "1.36.0")) {
buffer.push16(ADVANCED_TUNING.itermThrottleThreshold)
.push16(ADVANCED_TUNING.itermAcceleratorGain);
}
if (semver.gte(CONFIG.apiVersion, "1.39.0")) {
buffer.push16(ADVANCED_TUNING.dtermSetpointWeight);
if (semver.gte(CONFIG.apiVersion, "1.36.0")) {
buffer.push16(ADVANCED_TUNING.itermThrottleThreshold)
.push16(ADVANCED_TUNING.itermAcceleratorGain);
if (semver.gte(CONFIG.apiVersion, "1.39.0")) {
buffer.push16(ADVANCED_TUNING.dtermSetpointWeight);
if (semver.gte(CONFIG.apiVersion, "1.40.0")) {
buffer.push8(ADVANCED_TUNING.itermRotation)
.push8(ADVANCED_TUNING.smartFeedforward)
.push8(ADVANCED_TUNING.itermRelax)
.push8(ADVANCED_TUNING.itermRelaxType)
.push8(ADVANCED_TUNING.absoluteControlGain)
.push8(ADVANCED_TUNING.throttleBoost)
.push8(ADVANCED_TUNING.acroTrainerAngleLimit)
.push16(ADVANCED_TUNING.feedforwardRoll)
.push16(ADVANCED_TUNING.feedforwardPitch)
.push16(ADVANCED_TUNING.feedforwardYaw)
.push8(ADVANCED_TUNING.antiGravityMode);
}
}
}
}
}
// only supports 1 version pre bf 3.0
@ -1894,7 +1960,6 @@ MspHelper.prototype.sendCurrentConfig = function(onCompleteCallback) {
}
MspHelper.prototype.sendLedStripConfig = function(onCompleteCallback) {
var nextFunction = send_next_led_strip_config;

View file

@ -1,6 +1,8 @@
'use strict';
var mspHelper;
var connectionTimestamp;
function initializeSerialBackend() {
GUI.updateManualPortVisibility = function(){
@ -43,6 +45,8 @@ function initializeSerialBackend() {
thisElement.data("clicks", !clicks);
};
GUI.configuration_loaded = false;
var selected_baud = parseInt($('div#port-picker #baud').val());
var selected_port = $('div#port-picker #port option:selected').data().isManual ?
$('#port-override').val() :
@ -122,6 +126,15 @@ function initializeSerialBackend() {
function finishClose(finishedCallback) {
var wasConnected = CONFIGURATOR.connectionValid;
analytics.sendEvent(analytics.EVENT_CATEGORIES.FLIGHT_CONTROLLER, 'Disconnected');
if (connectionTimestamp) {
var connectedTime = Date.now() - connectionTimestamp;
analytics.sendTiming(analytics.EVENT_CATEGORIES.FLIGHT_CONTROLLER, 'Connected', connectedTime);
connectedTime = undefined;
}
analytics.resetFlightControllerData();
serial.disconnect(onClosed);
MSP.disconnect_cleanup();
@ -198,13 +211,17 @@ function onOpen(openInfo) {
// request configuration data
MSP.send_message(MSPCodes.MSP_API_VERSION, false, false, function () {
analytics.setFlightControllerData(analytics.DATA.API_VERSION, CONFIG.apiVersion);
GUI.log(i18n.getMessage('apiVersionReceived', [CONFIG.apiVersion]));
if (semver.gte(CONFIG.apiVersion, CONFIGURATOR.apiVersionAccepted)) {
MSP.send_message(MSPCodes.MSP_FC_VARIANT, false, false, function () {
analytics.setFlightControllerData(analytics.DATA.FIRMWARE_TYPE, CONFIG.flightControllerIdentifier);
if (CONFIG.flightControllerIdentifier === 'BTFL') {
MSP.send_message(MSPCodes.MSP_FC_VERSION, false, false, function () {
analytics.setFlightControllerData(analytics.DATA.FIRMWARE_VERSION, CONFIG.flightControllerVersion);
GUI.log(i18n.getMessage('fcInfoReceived', [CONFIG.flightControllerIdentifier, CONFIG.flightControllerVersion]));
updateStatusBarVersion(CONFIG.flightControllerVersion, CONFIG.flightControllerIdentifier);
@ -215,13 +232,19 @@ function onOpen(openInfo) {
GUI.log(i18n.getMessage('buildInfoReceived', [CONFIG.buildInfo]));
MSP.send_message(MSPCodes.MSP_BOARD_INFO, false, false, function () {
analytics.setFlightControllerData(analytics.DATA.BOARD_TYPE, CONFIG.boardIdentifier);
GUI.log(i18n.getMessage('boardInfoReceived', [CONFIG.boardIdentifier, CONFIG.boardVersion]));
updateStatusBarVersion(CONFIG.flightControllerVersion, CONFIG.flightControllerIdentifier, CONFIG.boardIdentifier);
updateTopBarVersion(CONFIG.flightControllerVersion, CONFIG.flightControllerIdentifier, CONFIG.boardIdentifier);
MSP.send_message(MSPCodes.MSP_UID, false, false, function () {
GUI.log(i18n.getMessage('uniqueDeviceIdReceived', [CONFIG.uid[0].toString(16) + CONFIG.uid[1].toString(16) + CONFIG.uid[2].toString(16)]));
var uniqueDeviceIdentifier = CONFIG.uid[0].toString(16) + CONFIG.uid[1].toString(16) + CONFIG.uid[2].toString(16);
analytics.setFlightControllerData(analytics.DATA.MCU_ID, objectHash.sha1(uniqueDeviceIdentifier));
analytics.sendEvent(analytics.EVENT_CATEGORIES.FLIGHT_CONTROLLER, 'Connected');
connectionTimestamp = Date.now();
GUI.log(i18n.getMessage('uniqueDeviceIdReceived', [uniqueDeviceIdentifier]));
if (semver.gte(CONFIG.apiVersion, "1.20.0")) {
MSP.send_message(MSPCodes.MSP_NAME, false, false, function () {
@ -238,6 +261,8 @@ function onOpen(openInfo) {
});
});
} else {
analytics.sendEvent(analytics.EVENT_CATEGORIES.FLIGHT_CONTROLLER, 'ConnectionRefused');
var dialog = $('.dialogConnectWarning')[0];
$('.dialogConnectWarning-content').html(i18n.getMessage('firmwareTypeNotSupported'));
@ -252,6 +277,8 @@ function onOpen(openInfo) {
}
});
} else {
analytics.sendEvent(analytics.EVENT_CATEGORIES.FLIGHT_CONTROLLER, 'ConnectionRefused');
var dialog = $('.dialogConnectWarning')[0];
$('.dialogConnectWarning-content').html(i18n.getMessage('firmwareVersionNotSupported', [CONFIGURATOR.apiVersionAccepted]));
@ -266,6 +293,8 @@ function onOpen(openInfo) {
}
});
} else {
analytics.sendEvent(analytics.EVENT_CATEGORIES.FLIGHT_CONTROLLER, 'SerialPortFailed');
console.log('Failed to open serial port');
GUI.log(i18n.getMessage('serialPortOpenFail'));
@ -297,7 +326,7 @@ function finishOpen() {
onConnect();
$('#tabs ul.mode-connected .tab_setup a').click();
GUI.selectDefaultTabWhenConnected();
}
function connectCli() {

View file

@ -20,7 +20,6 @@ TABS.adjustments.initialize = function (callback) {
}
function load_html() {
self.adjust_template();
$('#content').load("./tabs/adjustments.html", process_html);
}
@ -153,6 +152,8 @@ TABS.adjustments.initialize = function (callback) {
function process_html() {
self.adjust_template();
var auxChannelCount = RC.active_channels - 4;
var modeTableBodyElement = $('.tab-adjustments .adjustments tbody');
@ -272,14 +273,36 @@ TABS.adjustments.cleanup = function (callback) {
};
TABS.adjustments.adjust_template = function () {
var availableFunctionCount;
if (semver.lt(CONFIG.apiVersion, "1.31.0")) {
availableFunctionCount = 21; // Available in betaflight 2.9
var selectFunction = $('#functionSelectionSelect');
var elementsNumber;
if (semver.gte(CONFIG.apiVersion, "1.40.0")) {
elementsNumber = 29; // PID Audio
} else if (semver.gte(CONFIG.apiVersion, "1.39.0")) {
elementsNumber = 26; // PID Audio
} else if (semver.gte(CONFIG.apiVersion, "1.37.0")) {
elementsNumber = 25; // Horizon Strength
} else {
availableFunctionCount = 24; // RC rate Yaw / D setpoint / D setpoint transition added to 3.1.0
elementsNumber = 24; // Setpoint transition
}
for (let i = 0; i < elementsNumber; i++) {
selectFunction.append(new Option(i18n.getMessage('adjustmentsFunction' + i), i));
}
// For 1.40, the D Setpoint has been replaced, so we replace it with the correct values
if (semver.gte(CONFIG.apiVersion, "1.40.0")) {
var element22 = selectFunction.find("option[value='22']");
var element23 = selectFunction.find("option[value='23']");
// Change the "text"
element22.text(i18n.getMessage('adjustmentsFunction22_2'));
element23.text(i18n.getMessage('adjustmentsFunction23_2'));
// Reorder, we insert it with the other FF elements to be coherent...
element22.insertAfter(selectFunction.find("option[value='25']"));
element23.insertAfter(selectFunction.find("option[value='28']"));
}
var template = $('#tab-adjustments-templates .adjustments .adjustment');
var functionList = $(template).find('.functionSelection .function');
var functionListOptions = $(functionList).find('option').slice(0,availableFunctionCount);
functionList.empty().append(functionListOptions);
};

View file

@ -244,8 +244,9 @@ TABS.auxiliary.initialize = function (callback) {
}
function update_ui() {
for (var i = 0; i < AUX_CONFIG.length; i++) {
var modeElement = $('#mode-' + i);
let hasUsedMode = false;
for (let i = 0; i < AUX_CONFIG.length; i++) {
let modeElement = $('#mode-' + i);
if (modeElement.find(' .range').length == 0) {
// if the mode is unused, skip it
modeElement.removeClass('off').removeClass('on');
@ -257,8 +258,17 @@ TABS.auxiliary.initialize = function (callback) {
} else {
$('.mode .name').eq(i).data('modeElement').removeClass('on').addClass('off');
}
hasUsedMode = true;
}
let hideUnused = hideUnusedModes && hasUsedMode;
for (let i = 0; i < AUX_CONFIG.length; i++) {
let modeElement = $('#mode-' + i);
if (modeElement.find(' .range').length == 0) {
modeElement.toggle(!hideUnused);
}
}
auto_select_channel(RC.channels);
var auxChannelCount = RC.active_channels - 4;
@ -306,6 +316,18 @@ TABS.auxiliary.initialize = function (callback) {
return fillPrevChannelsValues();
}
let hideUnusedModes = false;
chrome.storage.local.get('hideUnusedModes', function (result) {
$("input#switch-toggle-unused")
.change(function() {
hideUnusedModes = $(this).prop("checked");
chrome.storage.local.set({ hideUnusedModes: hideUnusedModes });
update_ui();
})
.prop("checked", !!result.hideUnusedModes)
.change();
});
// update ui instantly on first load
update_ui();

View file

@ -60,14 +60,13 @@ TABS.cli.initialize = function (callback) {
var textarea = $('.tab-cli textarea');
$('.tab-cli .save').click(function() {
var prefix = 'cli';
var suffix = 'txt';
var filename = generateFilename(prefix, suffix);
var accepts = [{
extensions: [suffix],
description: suffix.toUpperCase() + ' files', extensions: [suffix],
}];
chrome.fileSystem.chooseEntry({type: 'saveFile', suggestedName: filename, accepts: accepts}, function(entry) {
@ -87,9 +86,11 @@ TABS.cli.initialize = function (callback) {
};
writer.onwriteend = function () {
if (writer.length === 0) {
if (self.outputHistory.length > 0 && writer.length === 0) {
writer.write(new Blob([self.outputHistory], {type: 'text/plain'}));
} else {
analytics.sendEvent(analytics.EVENT_CATEGORIES.FLIGHT_CONTROLLER, 'CliSave', self.outputHistory.length);
console.log('write complete');
}
};

View file

@ -2,7 +2,8 @@
TABS.configuration = {
DSHOT_PROTOCOL_MIN_VALUE: 5,
SHOW_OLD_BATTERY_CONFIG: false
SHOW_OLD_BATTERY_CONFIG: false,
analyticsChanges: {},
};
TABS.configuration.initialize = function (callback, scrollPosition) {
@ -10,6 +11,7 @@ TABS.configuration.initialize = function (callback, scrollPosition) {
if (GUI.active_tab != 'configuration') {
GUI.active_tab = 'configuration';
GUI.configuration_loaded = true;
}
if (semver.lt(CONFIG.apiVersion, "1.36.0")) {
@ -194,6 +196,10 @@ TABS.configuration.initialize = function (callback, scrollPosition) {
load_config();
function process_html() {
var self = this;
self.analyticsChanges = {};
var mixer_list_e = $('select.mixerList');
for (var selectIndex = 0; selectIndex < mixerList.length; selectIndex++) {
mixerList.forEach(function (mixerEntry, mixerIndex) {
@ -224,7 +230,15 @@ TABS.configuration.initialize = function (callback, scrollPosition) {
reverseMotorSwitch_e.prop('checked', MIXER_CONFIG.reverseMotorDir != 0).change();
mixer_list_e.change(function () {
MIXER_CONFIG.mixer = parseInt($(this).val());
var mixerValue = parseInt($(this).val());
var newValue;
if (mixerValue !== MIXER_CONFIG.mixer) {
newValue = $(this).find('option:selected').text();
}
self.analyticsChanges['Mixer'] = newValue;
MIXER_CONFIG.mixer = mixerValue;
refreshMixerPreview();
});
@ -355,11 +369,31 @@ TABS.configuration.initialize = function (callback, scrollPosition) {
esc_protocol_e.append('<option value="' + (i + 1) + '">'+ escprotocols[i] + '</option>');
}
esc_protocol_e.val(PID_ADVANCED_CONFIG.fast_pwm_protocol + 1);
$("input[id='unsyncedPWMSwitch']").change(function() {
if ($(this).is(':checked')) {
$('div.unsyncedpwmfreq').show();
} else {
$('div.unsyncedpwmfreq').hide();
}
});
$('input[id="unsyncedPWMSwitch"]').prop('checked', PID_ADVANCED_CONFIG.use_unsyncedPwm !== 0).change();
$('input[name="unsyncedpwmfreq"]').val(PID_ADVANCED_CONFIG.motor_pwm_rate);
$('input[name="digitalIdlePercent"]').val(PID_ADVANCED_CONFIG.digitalIdlePercent);
esc_protocol_e.val(PID_ADVANCED_CONFIG.fast_pwm_protocol + 1);
esc_protocol_e.change(function () {
var escProtocolValue = parseInt($(this).val()) - 1;
var newValue;
if (escProtocolValue !== PID_ADVANCED_CONFIG.fast_pwm_protocol) {
newValue = $(this).find('option:selected').text();
}
self.analyticsChanges['EscProtocol'] = newValue;
//hide not used setting for DSHOT protocol
if ($(this).val() - 1 >= self.DSHOT_PROTOCOL_MIN_VALUE) {
if (escProtocolValue >= self.DSHOT_PROTOCOL_MIN_VALUE) {
$('div.minthrottle').hide();
$('div.maxthrottle').hide();
$('div.mincommand').hide();
@ -379,9 +413,6 @@ TABS.configuration.initialize = function (callback, scrollPosition) {
}
}).change();
$('input[id="unsyncedPWMSwitch"]').prop('checked', PID_ADVANCED_CONFIG.use_unsyncedPwm !== 0);
$('input[name="unsyncedpwmfreq"]').val(PID_ADVANCED_CONFIG.motor_pwm_rate);
$('input[name="digitalIdlePercent"]').val(PID_ADVANCED_CONFIG.digitalIdlePercent);
// Gyro and PID update
var gyroUse32kHz_e = $('input[id="gyroUse32kHz"]');
@ -611,7 +642,15 @@ TABS.configuration.initialize = function (callback, scrollPosition) {
}
serialRX_e.change(function () {
RX_CONFIG.serialrx_provider = parseInt($(this).val());
var serialRxValue = parseInt($(this).val());
var newValue;
if (serialRxValue !== RX_CONFIG.serialrx_provider) {
newValue = $(this).find('option:selected').text();
}
self.analyticsChanges['SerialRx'] = newValue;
RX_CONFIG.serialrx_provider = serialRxValue;
});
// select current serial RX type
@ -921,14 +960,6 @@ TABS.configuration.initialize = function (callback, scrollPosition) {
checkUpdateCurrentControls();
}
$("input[id='unsyncedPWMSwitch']").change(function() {
if ($(this).is(':checked')) {
$('div.unsyncedpwmfreq').show();
} else {
$('div.unsyncedpwmfreq').hide();
}
}).change();
$('a.save').click(function () {
// gather data that doesn't have automatic change event bound
BOARD_ALIGNMENT_CONFIG.roll = parseInt($('input[name="board_align_roll"]').val());
@ -987,6 +1018,9 @@ TABS.configuration.initialize = function (callback, scrollPosition) {
RX_CONFIG.fpvCamAngleDegrees = parseInt($('input[name="fpvCamAngleDegrees"]').val());
}
analytics.sendChangeEvents(analytics.EVENT_CATEGORIES.FLIGHT_CONTROLLER, self.analyticsChanges);
self.analyticsChanges = {};
function save_serial_config() {
var next_callback = save_feature_config;
MSP.send_message(MSPCodes.MSP_SET_CF_SERIAL_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_CF_SERIAL_CONFIG), false, next_callback);

View file

@ -2,7 +2,8 @@
TABS.firmware_flasher = {
releases: null,
releaseChecker: new ReleaseChecker('firmware', 'https://api.github.com/repos/betaflight/betaflight/releases')
releaseChecker: new ReleaseChecker('firmware', 'https://api.github.com/repos/betaflight/betaflight/releases'),
jenkinsLoader: new JenkinsLoader('https://ci.betaflight.tech')
};
TABS.firmware_flasher.initialize = function (callback) {
@ -28,7 +29,7 @@ TABS.firmware_flasher.initialize = function (callback) {
: "normal");
}
$('#content').load("./tabs/firmware_flasher.html", function () {
function onDocumentLoad() {
FirmwareCache.load();
FirmwareCache.onPutToCache(onFirmwareCacheUpdate);
FirmwareCache.onRemoveFromCache(onFirmwareCacheUpdate);
@ -49,16 +50,18 @@ TABS.firmware_flasher.initialize = function (callback) {
function process_hex(data, summary) {
intel_hex = data;
analytics.setFirmwareData(analytics.DATA.FIRMWARE_CHECKSUM, objectHash.sha1(intel_hex));
parse_hex(intel_hex, function (data) {
parsed_hex = data;
if (parsed_hex) {
analytics.setFirmwareData(analytics.DATA.FIRMWARE_SIZE, parsed_hex.bytes_total);
if (!FirmwareCache.has(summary)) {
FirmwareCache.put(summary, intel_hex);
}
var url;
$('span.progressLabel').html('<a class="save_firmware" href="#" title="Save Firmware">Loaded Online Firmware: (' + parsed_hex.bytes_total + ' bytes)</a>');
$('a.flash_firmware').removeClass('disabled');
@ -243,24 +246,21 @@ TABS.firmware_flasher.initialize = function (callback) {
{
tag: 'firmwareFlasherOptionLabelBuildTypeReleaseCandidate',
loader: () => self.releaseChecker.loadReleaseData(releaseData => buildBoardOptions(releaseData, true))
},
{
tag: 'firmwareFlasherOptionLabelBuildTypeDevelopment',
loader: () => new JenkinsLoader('https://ci.betaflight.tech', 'Betaflight').loadBuilds(buildJenkinsBoardOptions)
},
{
tag: 'firmwareFlasherOptionLabelBuildTypeAKK3_3',
loader: () => new JenkinsLoader('https://ci.betaflight.tech', 'Betaflight Maintenance 3.3 (AKK - RDQ VTX Patch)').loadBuilds(buildJenkinsBoardOptions)
},
{
tag: 'firmwareFlasherOptionLabelBuildTypeAKK3_4',
loader: () => new JenkinsLoader('https://ci.betaflight.tech', 'Betaflight Maintenance 3.4 (AKK - RDQ VTX Patch)').loadBuilds(buildJenkinsBoardOptions)
}
];
var ciBuildsTypes = self.jenkinsLoader._jobs.map(job => {
return {
title: job.title,
loader: () => self.jenkinsLoader.loadBuilds(job.name, buildJenkinsBoardOptions)
};
})
buildTypes = buildTypes.concat(ciBuildsTypes);
var buildType_e = $('select[name="build_type"]');
buildTypes.forEach((build, index) => {
buildType_e.append($("<option value='{0}' selected>{1}</option>".format(index, i18n.getMessage(build.tag))))
buildType_e.append($("<option value='{0}' selected>{1}</option>".format(index, build.tag ? i18n.getMessage(build.tag) : build.title)))
});
showOrHideBuildTypeSelect();
@ -270,6 +270,8 @@ TABS.firmware_flasher.initialize = function (callback) {
i18n.localizePage();
buildType_e.change(function() {
analytics.setFirmwareData(analytics.DATA.FIRMWARE_CHANNEL, $(this).find('option:selected').text());
$("a.load_remote_file").addClass('disabled');
var build_type = $(this).val();
@ -325,7 +327,10 @@ TABS.firmware_flasher.initialize = function (callback) {
// UI Hooks
$('a.load_file').click(function () {
chrome.fileSystem.chooseEntry({type: 'openFile', accepts: [{extensions: ['hex']}]}, function (fileEntry) {
analytics.setFirmwareData(analytics.DATA.FIRMWARE_CHANNEL, undefined);
analytics.setFirmwareData(analytics.DATA.FIRMWARE_SOURCE, 'file');
chrome.fileSystem.chooseEntry({type: 'openFile', accepts: [{description: 'HEX files', extensions: ['hex']}]}, function (fileEntry) {
if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError.message);
@ -339,6 +344,7 @@ TABS.firmware_flasher.initialize = function (callback) {
console.log('Loading file from: ' + path);
fileEntry.file(function (file) {
analytics.setFirmwareData(analytics.DATA.FIRMWARE_NAME, file.name);
var reader = new FileReader();
reader.onprogress = function (e) {
@ -355,10 +361,14 @@ TABS.firmware_flasher.initialize = function (callback) {
intel_hex = e.target.result;
analytics.setFirmwareData(analytics.DATA.FIRMWARE_CHECKSUM, objectHash.sha1(intel_hex));
parse_hex(intel_hex, function (data) {
parsed_hex = data;
if (parsed_hex) {
analytics.setFirmwareData(analytics.DATA.FIRMWARE_SIZE, parsed_hex.bytes_total);
$('a.flash_firmware').removeClass('disabled');
$('span.progressLabel').text(i18n.getMessage('firmwareFlasherFirmwareLocalLoaded', parsed_hex.bytes_total));
@ -385,7 +395,10 @@ TABS.firmware_flasher.initialize = function (callback) {
let isCached = FirmwareCache.has(release);
if (evt.target.value=="0" || isCached) {
if (isCached) {
analytics.setFirmwareData(analytics.DATA.FIRMWARE_SOURCE, 'cache');
FirmwareCache.get(release, cached => {
analytics.setFirmwareData(analytics.DATA.FIRMWARE_NAME, release.file);
console.info("Release found in cache: " + release.file);
onLoadSuccess(cached.hexdata, release);
});
@ -398,6 +411,7 @@ TABS.firmware_flasher.initialize = function (callback) {
});
$('a.load_remote_file').click(function (evt) {
analytics.setFirmwareData(analytics.DATA.FIRMWARE_SOURCE, 'http');
if ($('select[name="firmware_version"]').val() == "0") {
GUI.log(i18n.getMessage('firmwareFlasherNoFirmwareSelected'));
@ -413,6 +427,7 @@ TABS.firmware_flasher.initialize = function (callback) {
var summary = $('select[name="firmware_version"] option:selected').data('summary');
if (summary) { // undefined while list is loading or while running offline
analytics.setFirmwareData(analytics.DATA.FIRMWARE_NAME, summary.file);
$("a.load_remote_file").text(i18n.getMessage('firmwareFlasherButtonDownloading'));
$("a.load_remote_file").addClass('disabled');
$.get(summary.url, onLoadSuccess).fail(failed_to_load);
@ -427,14 +442,17 @@ TABS.firmware_flasher.initialize = function (callback) {
if (parsed_hex != false) {
var options = {};
var eraseAll = false;
if ($('input.erase_chip').is(':checked')) {
options.erase_chip = true;
eraseAll = true
}
analytics.setFirmwareData(analytics.DATA.FIRMWARE_ERASE_ALL, eraseAll.toString());
if (String($('div#port-picker #port').val()) != 'DFU') {
if (String($('div#port-picker #port').val()) != '0') {
var port = String($('div#port-picker #port').val()),
baud;
var port = String($('div#port-picker #port').val()), baud;
baud = 115200;
if ($('input.updating').is(':checked')) {
@ -447,6 +465,7 @@ TABS.firmware_flasher.initialize = function (callback) {
baud = parseInt($('#flash_manual_baud_rate').val());
}
analytics.sendEvent(analytics.EVENT_CATEGORIES.FIRMWARE, 'Flashing');
STM32.connect(port, baud, parsed_hex, options);
} else {
@ -454,6 +473,8 @@ TABS.firmware_flasher.initialize = function (callback) {
GUI.log(i18n.getMessage('firmwareFlasherNoValidPort'));
}
} else {
analytics.sendEvent(analytics.EVENT_CATEGORIES.FIRMWARE, 'Flashing');
STM32DFU.connect(usbDevices.STM32DFU, parsed_hex, options);
}
} else {
@ -465,7 +486,7 @@ TABS.firmware_flasher.initialize = function (callback) {
$(document).on('click', 'span.progressLabel a.save_firmware', function () {
var summary = $('select[name="firmware_version"] option:selected').data('summary');
chrome.fileSystem.chooseEntry({type: 'saveFile', suggestedName: summary.file, accepts: [{extensions: ['hex']}]}, function (fileEntry) {
chrome.fileSystem.chooseEntry({type: 'saveFile', suggestedName: summary.file, accepts: [{description: 'HEX files', extensions: ['hex']}]}, function (fileEntry) {
if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError.message);
return;
@ -626,6 +647,10 @@ TABS.firmware_flasher.initialize = function (callback) {
});
GUI.content_ready(callback);
}
self.jenkinsLoader.loadJobs('Firmware', () => {
$('#content').load("./tabs/firmware_flasher.html", onDocumentLoad);
});
};
@ -637,5 +662,7 @@ TABS.firmware_flasher.cleanup = function (callback) {
$(document).unbind('keypress');
$(document).off('click', 'span.progressLabel a');
analytics.resetFirmwareData();
if (callback) callback();
};

View file

@ -32,6 +32,26 @@ TABS.landing.initialize = function (callback) {
$(this).data('state2', state);
});
// load privacy policy content
$('#privacy_policy .policy').load('./tabs/privacy_policy.html');
/** changelog trigger **/
$("#privacy_policy_toggle").on('click', function() {
var state = $(this).data('state2');
if (state) {
$("#privacy_policy").animate({right: -495}, 200, function () {
$("#content").removeClass('policy_open');
});
state = false;
} else {
$("#privacy_policy").animate({right: 0}, 200);
$("#content").addClass('policy_open');
state = true;
}
$(this).text(state ? i18n.getMessage('close') : i18n.getMessage('defaultPrivacyPolicyAction'));
$(this).data('state2', state);
});
GUI.content_ready(callback);
});

View file

@ -236,7 +236,7 @@ TABS.logging.initialize = function (callback) {
var filename = generateFilename(prefix, suffix);
var accepts = [{
extensions: [suffix],
description: suffix.toUpperCase() + ' files', extensions: [suffix],
}];
// create or load the file

View file

@ -45,7 +45,11 @@ TABS.motors.initialize = function (callback) {
}
function load_motor_data() {
MSP.send_message(MSPCodes.MSP_MOTOR, false, false, load_html);
MSP.send_message(MSPCodes.MSP_MOTOR, false, false, load_mixer_config);
}
function load_mixer_config() {
MSP.send_message(MSPCodes.MSP_MIXER_CONFIG, false, false, load_html);
}
function load_html() {

View file

@ -145,6 +145,22 @@ TABS.onboard_logging.initialize = function (callback) {
$("div.blackboxRate").show();
}
}).change();
if (semver.gte(CONFIG.apiVersion, "1.40.0")) {
if (SDCARD.supported || DATAFLASH.supported) {
$(".tab-onboard_logging")
.toggleClass("msc-supported", true);
$('a.onboardLoggingRebootMsc').click(function () {
analytics.sendEvent(analytics.EVENT_CATEGORIES.FLIGHT_CONTROLLER, 'RebootMsc');
var buffer = [];
buffer.push(2);
MSP.send_message(MSPCodes.MSP_SET_REBOOT, buffer, false);
});
}
}
update_html();
@ -284,6 +300,8 @@ TABS.onboard_logging.initialize = function (callback) {
}
function update_html() {
var dataflashPresent = DATAFLASH.totalSize > 0;
update_bar_width($(".tab-onboard_logging .dataflash-used"), DATAFLASH.usedSize, DATAFLASH.totalSize, i18n.getMessage('dataflashUsedSpace'), false);
update_bar_width($(".tab-onboard_logging .dataflash-free"), DATAFLASH.totalSize - DATAFLASH.usedSize, DATAFLASH.totalSize, i18n.getMessage('dataflashFreeSpace'), false);
@ -296,27 +314,51 @@ TABS.onboard_logging.initialize = function (callback) {
.toggleClass("sdcard-error", SDCARD.state === MSP.SDCARD_STATE_FATAL)
.toggleClass("sdcard-initializing", SDCARD.state === MSP.SDCARD_STATE_CARD_INIT || SDCARD.state === MSP.SDCARD_STATE_FS_INIT)
.toggleClass("sdcard-ready", SDCARD.state === MSP.SDCARD_STATE_READY);
if (semver.gte(CONFIG.apiVersion, "1.40.0")) {
var mscIsReady = dataflashPresent || (SDCARD.state === MSP.SDCARD_STATE_READY);
$(".tab-onboard_logging")
.toggleClass("msc-not-ready", !mscIsReady);
if (!mscIsReady) {
$('a.onboardLoggingRebootMsc').addClass('disabled');
} else {
$('a.onboardLoggingRebootMsc').removeClass('disabled');
}
}
var loggingStatus
switch (SDCARD.state) {
case MSP.SDCARD_STATE_NOT_PRESENT:
$(".sdcard-status").text(i18n.getMessage('sdcardStatusNoCard'));
loggingStatus = 'SdCard: NotPresent';
break;
case MSP.SDCARD_STATE_FATAL:
$(".sdcard-status").html(i18n.getMessage('sdcardStatusReboot'));
loggingStatus = 'SdCard: Error';
break;
case MSP.SDCARD_STATE_READY:
$(".sdcard-status").text(i18n.getMessage('sdcardStatusReady'));
loggingStatus = 'SdCard: Ready';
break;
case MSP.SDCARD_STATE_CARD_INIT:
$(".sdcard-status").text(i18n.getMessage('sdcardStatusStarting'));
loggingStatus = 'SdCard: Init';
break;
case MSP.SDCARD_STATE_FS_INIT:
$(".sdcard-status").text(i18n.getMessage('sdcardStatusFileSystem'));
loggingStatus = 'SdCard: FsInit';
break;
default:
$(".sdcard-status").text(i18n.getMessage('sdcardStatusUnknown',[SDCARD.state]));
}
if (dataflashPresent && SDCARD.state === MSP.SDCARD_STATE_NOT_PRESENT) {
loggingStatus = 'Dataflash';
analytics.setFlightControllerData(analytics.DATA.LOG_SIZE, DATAFLASH.usedSize);
}
analytics.setFlightControllerData(analytics.DATA.LOGGING_STATUS, loggingStatus);
if (SDCARD.supported && !sdcardTimer) {
// Poll for changes in SD card status
sdcardTimer = setTimeout(function() {
@ -348,6 +390,8 @@ TABS.onboard_logging.initialize = function (callback) {
}
function mark_saving_dialog_done(startTime, totalBytes, totalBytesCompressed) {
analytics.sendEvent(analytics.EVENT_CATEGORIES.FLIGHT_CONTROLLER, 'SaveDataflash');
var totalTime = (new Date().getTime() - startTime) / 1000;
console.log('Received ' + totalBytes + ' bytes in ' + totalTime.toFixed(2) + 's ('
+ (totalBytes / totalTime / 1024).toFixed(2) + 'kB / s) with block size ' + self.blockSize + '.');
@ -445,7 +489,7 @@ TABS.onboard_logging.initialize = function (callback) {
var filename = generateFilename(prefix, suffix);
chrome.fileSystem.chooseEntry({type: 'saveFile', suggestedName: filename,
accepts: [{extensions: [suffix]}]}, function(fileEntry) {
accepts: [{description: suffix.toUpperCase() + ' files', extensions: [suffix]}]}, function(fileEntry) {
var error = chrome.runtime.lastError;
if (error) {
@ -513,6 +557,9 @@ TABS.onboard_logging.initialize = function (callback) {
};
TABS.onboard_logging.cleanup = function (callback) {
analytics.setFlightControllerData(analytics.DATA.LOGGING_STATUS, undefined);
analytics.setFlightControllerData(analytics.DATA.LOG_SIZE, undefined);
if (sdcardTimer) {
clearTimeout(sdcardTimer);
sdcardTimer = false;

View file

@ -129,7 +129,7 @@ FONT.parseMCMFontFile = function(data) {
FONT.openFontFile = function($preview) {
return new Promise(function(resolve) {
chrome.fileSystem.chooseEntry({type: 'openFile', accepts: [{extensions: ['mcm']}]}, function (fileEntry) {
chrome.fileSystem.chooseEntry({type: 'openFile', accepts: [{description: 'MCM files', extensions: ['mcm']}]}, function (fileEntry) {
FONT.data.loaded_font_file = fileEntry.name;
if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError.message);
@ -342,7 +342,7 @@ OSD.constants = {
default_position: -9,
draw_order: 110,
positionable: true,
preview: FONT.symbol(SYM.THR) + FONT.symbol(SYM.THR1) + '69'
preview: FONT.symbol(SYM.THR) + FONT.symbol(SYM.THR1) + ' 69'
},
CPU_LOAD: {
name: 'CPU_LOAD',
@ -913,7 +913,8 @@ OSD.constants = {
{ file: "extra_large", name: "Extra Large" },
{ file: "betaflight", name: "Betaflight" },
{ file: "digital", name: "Digital" },
{ file: "clarity", name: "Clarity" }
{ file: "clarity", name: "Clarity" },
{ file: "vision", name: "Vision" }
]
};
@ -1470,17 +1471,18 @@ TABS.osd.initialize = function (callback) {
}
$('#content').load("./tabs/osd.html", function () {
// Generate font type buttons
var fontbuttons = $('.fontbuttons');
// Generate font type select element
var fontselect = $('.fontpresets');
OSD.constants.FONT_TYPES.forEach(function(e, i) {
var button = $('<button>', {
var option = $('<option>', {
"data-font-file": e.file,
value: e.file,
text: e.name
});
fontbuttons.append($(button));
fontselect.append($(option));
});
var fontbuttons = $('.fontpresets_wrapper');
fontbuttons.append($('<button>', { class: "load_font_file", i18n: "osdSetupOpenFont" }));
// must invoke before i18n.localizePage() since it adds translation keys for expected logo size
@ -1974,24 +1976,27 @@ TABS.osd.initialize = function (callback) {
// init structs once, also clears current font
FONT.initData();
var $fontPicker = $('.fontbuttons button');
$fontPicker.click(function(e) {
if (!$(this).data('font-file')) { return; }
$fontPicker.removeClass('active');
$(this).addClass('active');
$.get('./resources/osd/' + $(this).data('font-file') + '.mcm', function(data) {
var $fontpresets = $('.fontpresets')
$fontpresets.change(function(e) {
var $font = $('.fontpresets option:selected');
$.get('./resources/osd/' + $font.data('font-file') + '.mcm', function(data) {
FONT.parseMCMFontFile(data);
FONT.preview($preview);
LogoManager.drawPreview();
updateOsdView();
});
});
// load the first font when we change tabs
$fontPicker.first().click();
var $font = $('.fontpresets option:selected');
$.get('./resources/osd/' + $font.data('font-file') + '.mcm', function(data) {
FONT.parseMCMFontFile(data);
FONT.preview($preview);
LogoManager.drawPreview();
updateOsdView();
});
$('button.load_font_file').click(function() {
$fontPicker.removeClass('active');
FONT.openFontFile().then(function() {
FONT.preview($preview);
LogoManager.drawPreview();
@ -2047,7 +2052,7 @@ TABS.osd.initialize = function (callback) {
})
$(document).on('click', 'span.progressLabel a.save_font', function () {
chrome.fileSystem.chooseEntry({type: 'saveFile', suggestedName: 'baseflight', accepts: [{extensions: ['mcm']}]}, function (fileEntry) {
chrome.fileSystem.chooseEntry({type: 'saveFile', suggestedName: 'baseflight', accepts: [{description: 'MCM files', extensions: ['mcm']}]}, function (fileEntry) {
if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError.message);
return;

441
src/js/tabs/pid_tuning.js Executable file → Normal file
View file

@ -39,9 +39,13 @@ TABS.pid_tuning.initialize = function (callback) {
}).then(function() {
return MSP.promise(MSPCodes.MSP_RC_DEADBAND);
}).then(function() {
$('#content').load("./tabs/pid_tuning.html", process_html);
MSP.send_message(MSPCodes.MSP_MIXER_CONFIG, false, false, load_html);
});
function load_html() {
$('#content').load("./tabs/pid_tuning.html", process_html);
}
function pid_and_rc_to_form() {
self.setProfile();
if (semver.gte(CONFIG.apiVersion, "1.20.0")) {
@ -49,142 +53,19 @@ TABS.pid_tuning.initialize = function (callback) {
}
// Fill in the data from PIDs array
var i = 0;
$('.pid_tuning .ROLL input').each(function () {
switch (i) {
case 0:
$(this).val(PIDs[0][i++]);
break;
case 1:
$(this).val(PIDs[0][i++]);
break;
case 2:
$(this).val(PIDs[0][i++]);
break;
}
});
i = 0;
$('.pid_tuning .PITCH input').each(function () {
switch (i) {
case 0:
$(this).val(PIDs[1][i++]);
break;
case 1:
$(this).val(PIDs[1][i++]);
break;
case 2:
$(this).val(PIDs[1][i++]);
break;
}
});
// For each pid name
PID_names.forEach(function(elementPid, indexPid) {
i = 0;
$('.pid_tuning .YAW input').each(function () {
switch (i) {
case 0:
$(this).val(PIDs[2][i++]);
break;
case 1:
$(this).val(PIDs[2][i++]);
break;
}
});
$('.pid_tuning .YAW_JUMP_PREVENTION input').each(function () {
switch (i) {
case 2:
$(this).val(PIDs[2][i++]);
break;
}
});
// Look into the PID table to a row with the name of the pid
var searchRow = $('.pid_tuning .' + elementPid + ' input');
i = 0;
$('.pid_tuning .ALT input').each(function () {
switch (i) {
case 0:
$(this).val(PIDs[3][i++]);
break;
case 1:
$(this).val(PIDs[3][i++]);
break;
case 2:
$(this).val(PIDs[3][i++]);
break;
}
});
i = 0;
$('.pid_tuning .Pos input').each(function () {
$(this).val(PIDs[4][i++]);
});
i = 0;
$('.pid_tuning .PosR input').each(function () {
switch (i) {
case 0:
$(this).val(PIDs[5][i++]);
break;
case 1:
$(this).val(PIDs[5][i++]);
break;
case 2:
$(this).val(PIDs[5][i++]);
break;
}
});
i = 0;
$('.pid_tuning .NavR input').each(function () {
switch (i) {
case 0:
$(this).val(PIDs[6][i++]);
break;
case 1:
$(this).val(PIDs[6][i++]);
break;
case 2:
$(this).val(PIDs[6][i++]);
break;
}
});
i = 0;
$('.pid_tuning .ANGLE input').each(function () {
switch (i) {
case 0:
$(this).val(PIDs[7][i++]);
break;
}
});
$('.pid_tuning .HORIZON input').each(function () {
switch (i) {
case 1:
$(this).val(PIDs[7][i++]);
break;
case 2:
$(this).val(PIDs[7][i++]);
break;
}
});
i = 0;
$('.pid_tuning .MAG input').each(function () {
$(this).val(PIDs[8][i++]);
});
i = 0;
$('.pid_tuning .Vario input').each(function () {
switch (i) {
case 0:
$(this).val(PIDs[9][i++]);
break;
case 1:
$(this).val(PIDs[9][i++]);
break;
case 2:
$(this).val(PIDs[9][i++]);
break;
}
// Assign each value
searchRow.each(function (indexInput) {
if (PIDs[indexPid][indexInput] !== undefined) {
$(this).val(PIDs[indexPid][indexInput]);
}
});
});
// Fill in data from RC_tuning object
@ -299,6 +180,129 @@ TABS.pid_tuning.initialize = function (callback) {
$('.dtermLowpass2').hide();
}
if (semver.gte(CONFIG.apiVersion, "1.40.0")) {
// I Term Rotation
$('input[id="itermrotation"]').prop('checked', ADVANCED_TUNING.itermRotation !== 0);
// Smart Feed Forward
$('input[id="smartfeedforward"]').prop('checked', ADVANCED_TUNING.smartFeedforward !== 0);
// I Term Relax
var itermRelaxCheck = $('input[id="itermrelax"]');
itermRelaxCheck.prop('checked', ADVANCED_TUNING.itermRelax !== 0);
$('select[id="itermrelaxAxes"]').val(ADVANCED_TUNING.itermRelax > 0 ? ADVANCED_TUNING.itermRelax : 1);
$('select[id="itermrelaxType"]').val(ADVANCED_TUNING.itermRelaxType);
itermRelaxCheck.change(function() {
var checked = $(this).is(':checked');
if (checked) {
$('.itermrelax .suboption').show();
} else {
$('.itermrelax .suboption').hide();
}
});
itermRelaxCheck.change();
// Absolute Control
var absoluteControlGainNumberElement = $('input[name="absoluteControlGain-number"]');
var absoluteControlGainRangeElement = $('input[name="absoluteControlGain-range"]');
absoluteControlGainNumberElement.change(function () {
absoluteControlGainRangeElement.val($(this).val());
});
absoluteControlGainRangeElement.change(function () {
absoluteControlGainNumberElement.val($(this).val());
});
absoluteControlGainNumberElement.val(ADVANCED_TUNING.absoluteControlGain).change();
// Throttle Boost
var throttleBoostNumberElement = $('input[name="throttleBoost-number"]');
var throttleBoostRangeElement = $('input[name="throttleBoost-range"]');
throttleBoostNumberElement.change(function () {
throttleBoostRangeElement.val($(this).val());
});
throttleBoostRangeElement.change(function () {
throttleBoostNumberElement.val($(this).val());
});
throttleBoostNumberElement.val(ADVANCED_TUNING.throttleBoost).change();
// Acro Trainer
var acroTrainerAngleLimitNumberElement = $('input[name="acroTrainerAngleLimit-number"]');
var acroTrainerAngleLimitRangeElement = $('input[name="acroTrainerAngleLimit-range"]');
acroTrainerAngleLimitNumberElement.change(function () {
acroTrainerAngleLimitRangeElement.val($(this).val());
});
acroTrainerAngleLimitRangeElement.change(function () {
acroTrainerAngleLimitNumberElement.val($(this).val());
});
acroTrainerAngleLimitNumberElement.val(ADVANCED_TUNING.acroTrainerAngleLimit).change();
// Yaw D
$('.pid_tuning .YAW input[name="d"]').val(PIDs[2][2]); // PID Yaw D
// Feedforward
$('.pid_tuning .ROLL input[name="f"]').val(ADVANCED_TUNING.feedforwardRoll);
$('.pid_tuning .PITCH input[name="f"]').val(ADVANCED_TUNING.feedforwardPitch);
$('.pid_tuning .YAW input[name="f"]').val(ADVANCED_TUNING.feedforwardYaw);
var feedforwardTransitionNumberElement = $('input[name="feedforwardTransition-number"]');
var feedforwardTransitionRangeElement = $('input[name="feedforwardTransition-range"]');
feedforwardTransitionNumberElement.val(ADVANCED_TUNING.feedforwardTransition / 100);
feedforwardTransitionRangeElement.val(ADVANCED_TUNING.feedforwardTransition / 100);
feedforwardTransitionNumberElement.change(function () {
feedforwardTransitionRangeElement.val($(this).val());
});
feedforwardTransitionRangeElement.change(function () {
feedforwardTransitionNumberElement.val($(this).val());
});
$('.helpicon[i18n_title="pidTuningPidTuningTip"]').hide();
// AntiGravity Mode
var antiGravityModeSelect = $('.antigravity select[id="antiGravityMode"]');
antiGravityModeSelect.change(function () {
var antiGravityModeValue = $('.antigravity select[id="antiGravityMode"]').val();
// Smooth
if (antiGravityModeValue == 0) {
$('.antigravity table th:nth-child(3)').hide();
$('.antigravity table td:nth-child(3)').hide();
} else {
$('.antigravity table th:nth-child(3)').show();
$('.antigravity table td:nth-child(3)').show();
}
});
antiGravityModeSelect.val(ADVANCED_TUNING.antiGravityMode).change();
} else {
$('.itermrotation').hide();
$('.smartfeedforward').hide();
$('.itermrelax').hide();
$('.absoluteControlGain').hide();
$('.throttleBoost').hide();
$('.acroTrainerAngleLimit').hide();
$('.pid_tuning .YAW input[name="d"]').hide();
// Feedforward column
$('#pid_main tr :nth-child(5)').hide();
$('#pid_main .pid_titlebar2 th').attr("colspan", 8);
$('.helpicon[i18n_title="pidTuningPidTuningTipFeedforward"]').hide();
$('#pid-tuning .feedforwardTransition').hide();
$('.antigravity table th:first-child').hide();
$('.antigravity table td:first-child').hide();
}
$('input[id="gyroNotch1Enabled"]').change(function() {
var checked = $(this).is(':checked');
var hz = FILTER_CONFIG.gyro_notch_hz > 0 ? FILTER_CONFIG.gyro_notch_hz : DEFAULT.gyro_notch_hz;
@ -409,60 +413,19 @@ TABS.pid_tuning.initialize = function (callback) {
function form_to_pid_and_rc() {
// Fill in the data from PIDs array
// Catch all the changes and stuff the inside PIDs array
var i = 0;
$('table.pid_tuning tr.ROLL .pid_data input').each(function () {
PIDs[0][i++] = parseFloat($(this).val());
});
i = 0;
$('table.pid_tuning tr.PITCH .pid_data input').each(function () {
PIDs[1][i++] = parseFloat($(this).val());
});
// For each pid name
PID_names.forEach(function(elementPid, indexPid) {
i = 0;
$('table.pid_tuning tr.YAW .pid_data input').each(function () {
PIDs[2][i++] = parseFloat($(this).val());
});
$('table.pid_tuning tr.YAW_JUMP_PREVENTION .pid_data input').each(function () {
PIDs[2][i++] = parseFloat($(this).val());
});
// Look into the PID table to a row with the name of the pid
var searchRow = $('.pid_tuning .' + elementPid + ' input');
i = 0;
$('table.pid_tuning tr.ALT input').each(function () {
PIDs[3][i++] = parseFloat($(this).val());
});
i = 0;
$('table.pid_tuning tr.Vario input').each(function () {
PIDs[9][i++] = parseFloat($(this).val());
});
i = 0;
$('table.pid_tuning tr.Pos input').each(function () {
PIDs[4][i++] = parseFloat($(this).val());
});
i = 0;
$('table.pid_tuning tr.PosR input').each(function () {
PIDs[5][i++] = parseFloat($(this).val());
});
i = 0;
$('table.pid_tuning tr.NavR input').each(function () {
PIDs[6][i++] = parseFloat($(this).val());
});
i = 0;
$('div.pid_tuning tr.ANGLE input').each(function () {
PIDs[7][i++] = parseFloat($(this).val());
});
$('div.pid_tuning tr.HORIZON input').each(function () {
PIDs[7][i++] = parseFloat($(this).val());
});
i = 0;
$('div.pid_tuning tr.MAG input').each(function () {
PIDs[8][i++] = parseFloat($(this).val());
// Assign each value
searchRow.each(function (indexInput) {
if ($(this).val()) {
PIDs[indexPid][indexInput] = parseFloat($(this).val());
}
});
});
// catch RC_tuning changes
@ -527,40 +490,80 @@ TABS.pid_tuning.initialize = function (callback) {
FILTER_CONFIG.gyro_lowpass2_type = parseInt($('.pid_filter select[name="gyroLowpass2Type"]').val());
FILTER_CONFIG.dterm_lowpass2_hz = parseInt($('.pid_filter input[name="dtermLowpass2Frequency"]').val());
}
if (semver.gte(CONFIG.apiVersion, "1.40.0")) {
ADVANCED_TUNING.itermRotation = $('input[id="itermrotation"]').is(':checked') ? 1 : 0;
ADVANCED_TUNING.smartFeedforward = $('input[id="smartfeedforward"]').is(':checked') ? 1 : 0;
ADVANCED_TUNING.itermRelax = $('input[id="itermrelax"]').is(':checked') ? $('select[id="itermrelaxAxes"]').val() : 0;
ADVANCED_TUNING.itermRelaxType = $('input[id="itermrelax"]').is(':checked') ? $('select[id="itermrelaxType"]').val() : 0;
ADVANCED_TUNING.absoluteControlGain = $('input[name="absoluteControlGain-number"]').val();
ADVANCED_TUNING.throttleBoost = $('input[name="throttleBoost-number"]').val();
ADVANCED_TUNING.acroTrainerAngleLimit = $('input[name="acroTrainerAngleLimit-number"]').val();
ADVANCED_TUNING.feedforwardRoll = parseInt($('.pid_tuning .ROLL input[name="f"]').val());
ADVANCED_TUNING.feedforwardPitch = parseInt($('.pid_tuning .PITCH input[name="f"]').val());
ADVANCED_TUNING.feedforwardYaw = parseInt($('.pid_tuning .YAW input[name="f"]').val());
ADVANCED_TUNING.feedforwardTransition = parseInt($('input[name="feedforwardTransition-number"]').val() * 100);
ADVANCED_TUNING.antiGravityMode = $('select[id="antiGravityMode"]').val();
}
}
function showAllPids() {
$('.tab-pid_tuning .pid_tuning').show();
// Hide all optional elements
$('.pid_optional tr').hide(); // Hide all rows
$('.pid_optional table').hide(); // Hide tables
$('.pid_optional').hide(); // Hide general div
// Only show rows supported by the firmware
PID_names.forEach(function(elementPid) {
// Show rows for the PID
$('.pid_tuning .' + elementPid).show();
// Show titles and other elements needed by the PID
$('.needed_by_' + elementPid).show();
});
// Special case
if (semver.lt(CONFIG.apiVersion, "1.24.0")) {
$('#pid_sensitivity').hide();
}
}
function hideUnusedPids() {
$('.tab-pid_tuning .pid_tuning').hide();
$('#pid_main').show();
if (have_sensor(CONFIG.activeSensors, 'acc')) {
$('#pid_accel').show();
$('#pid_level').show();
$('#pid_sensitivity').show();
if (!have_sensor(CONFIG.activeSensors, 'acc')) {
$('#pid_accel').hide();
}
var showTitle = false;
if (have_sensor(CONFIG.activeSensors, 'baro') ||
have_sensor(CONFIG.activeSensors, 'sonar')) {
$('#pid_baro').show();
showTitle = true;
}
if (have_sensor(CONFIG.activeSensors, 'mag')) {
$('#pid_mag').show();
showTitle = true;
}
if (FEATURE_CONFIG.features.isEnabled('GPS')) {
$('#pid_gps').show();
showTitle = true;
var hideSensorPid = function(element, sensorReady) {
var isVisible = element.is(":visible");
if (!isVisible || !sensorReady) {
element.hide();
isVisible = false;
}
return isVisible;
}
if (showTitle) {
$('#pid_optional').show();
var isVisibleBaroMagGps = false;
isVisibleBaroMagGps |= hideSensorPid($('#pid_baro'), have_sensor(CONFIG.activeSensors, 'baro') || have_sensor(CONFIG.activeSensors, 'sonar'));
isVisibleBaroMagGps |= hideSensorPid($('#pid_mag'), have_sensor(CONFIG.activeSensors, 'mag'));
isVisibleBaroMagGps |= hideSensorPid($('#pid_gps'), have_sensor(CONFIG.activeSensors, 'GPS'));
if (!isVisibleBaroMagGps) {
$('#pid_baro_mag_gps').hide();
}
}
@ -742,6 +745,7 @@ TABS.pid_tuning.initialize = function (callback) {
}
}
showAllPids();
updatePidDisplay();
showAllButton.on('click', function(){
@ -850,12 +854,16 @@ TABS.pid_tuning.initialize = function (callback) {
$('.tab-pid_tuning .note').hide();
}
// Add a name to each row of PIDs if empty
$('.pid_tuning tr').each(function(){
for(i = 0; i < PID_names.length; i++) {
if($(this).hasClass(PID_names[i])) {
$(this).find('td:first').text(PID_names[i]);
for(i = 0; i < PID_names.length; i++) {
if($(this).hasClass(PID_names[i])) {
var firstColumn = $(this).find('td:first');
if (!firstColumn.text()) {
firstColumn.text(PID_names[i]);
}
}
}
}
});
@ -1372,8 +1380,13 @@ TABS.pid_tuning.updatePidControllerParameters = function () {
} else {
$('.pid_tuning .YAW_JUMP_PREVENTION').hide();
$('#pid-tuning .dtermSetpointTransition').show();
$('#pid-tuning .dtermSetpoint').show();
if (semver.gte(CONFIG.apiVersion, "1.40.0")) {
$('#pid-tuning .dtermSetpointTransition').hide();
$('#pid-tuning .dtermSetpoint').hide();
} else {
$('#pid-tuning .dtermSetpointTransition').show();
$('#pid-tuning .dtermSetpoint').show();
}
$('#pid-tuning .delta').hide();
}

View file

@ -1,6 +1,8 @@
'use strict';
TABS.ports = {};
TABS.ports = {
analyticsChanges: {},
};
TABS.ports.initialize = function (callback, scrollPosition) {
var self = this;
@ -117,6 +119,9 @@ TABS.ports.initialize = function (callback, scrollPosition) {
}
function update_ui() {
self.analyticsChanges = {};
self.foo.bar = 1;
if (semver.lt(CONFIG.apiVersion, "1.6.0")) {
@ -240,6 +245,19 @@ TABS.ports.initialize = function (callback, scrollPosition) {
if (serialPort.functions.indexOf(functionName) >= 0) {
select_e.val(functionName);
}
if (column === 'telemetry') {
var initialValue = functionName;
select_e.change(function () {
var telemetryValue = $(this).val();
var newValue;
if (telemetryValue !== initialValue) {
newValue = $(this).find('option:selected').text();
}
self.analyticsChanges['Telemetry'] = newValue;
});
}
}
}
}
@ -249,6 +267,7 @@ TABS.ports.initialize = function (callback, scrollPosition) {
}
function on_tab_loaded_handler() {
var self = this;
i18n.localizePage();
@ -265,6 +284,9 @@ TABS.ports.initialize = function (callback, scrollPosition) {
}
function on_save_handler() {
analytics.sendChangeEvents(analytics.EVENT_CATEGORIES.FLIGHT_CONTROLLER, self.analyticsChanges);
self.analyticsChanges = {};
// update configuration based on current ui state
SERIAL_CONFIG.ports = [];

View file

@ -40,7 +40,7 @@ TABS.receiver.initialize = function (callback) {
}
function load_rx_config() {
var next_callback = load_html;
var next_callback = load_mixer_config;
if (semver.gte(CONFIG.apiVersion, "1.20.0")) {
MSP.send_message(MSPCodes.MSP_RX_CONFIG, false, false, next_callback);
} else {
@ -48,6 +48,10 @@ TABS.receiver.initialize = function (callback) {
}
}
function load_mixer_config() {
MSP.send_message(MSPCodes.MSP_MIXER_CONFIG, false, false, load_html);
}
function load_html() {
$('#content').load("./tabs/receiver.html", process_html);
}

View file

@ -59,9 +59,24 @@ TABS.setup.initialize = function (callback) {
self.initializeInstruments();
$('#arming-disable-flag-row').attr('title', i18n.getMessage('initialSetupArmingDisableFlagsTooltip'));
if (semver.gte(CONFIG.apiVersion, "1.40.0")) {
if (isExpertModeEnabled()) {
$('.initialSetupRebootBootloader').show();
} else {
$('.initialSetupRebootBootloader').hide();
}
$('a.rebootBootloader').click(function () {
var buffer = [];
buffer.push(1);
MSP.send_message(MSPCodes.MSP_SET_REBOOT, buffer, false);
});
} else {
$('.initialSetupRebootBootloader').hide();
}
// UI Hooks
$('a.calibrateAccel').click(function () {
var self = $(this);