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:
commit
f4ea605685
45 changed files with 18196 additions and 463 deletions
156
src/js/Analytics.js
Normal file
156
src/js/Analytics.js
Normal 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();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -26,7 +26,7 @@ var LogoManager = LogoManager || {
|
|||
},
|
||||
// config for logo image selection dialog
|
||||
acceptFileTypes: [
|
||||
{ extensions: ['png', 'bmp'] },
|
||||
{ description: 'images', extensions: ['png', 'bmp'] },
|
||||
],
|
||||
};
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
12
src/js/fc.js
12
src/js/fc.js
|
@ -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 = {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
|
|
130
src/js/main.js
130
src/js/main.js
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
441
src/js/tabs/pid_tuning.js
Executable file → Normal 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();
|
||||
}
|
||||
|
|
|
@ -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 = [];
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue