diff --git a/js/Features.js b/js/Features.js
new file mode 100644
index 00000000..793bcada
--- /dev/null
+++ b/js/Features.js
@@ -0,0 +1,144 @@
+'use strict;'
+
+var Features = function (config) {
+ var features = [
+ {bit: 0, group: 'rxMode', mode: 'group', name: 'RX_PPM'},
+ {bit: 1, group: 'batteryVoltage', name: 'VBAT'},
+ {bit: 2, group: 'other', name: 'INFLIGHT_ACC_CAL'},
+ {bit: 3, group: 'rxMode', mode: 'group', name: 'RX_SERIAL'},
+ {bit: 4, group: 'esc', name: 'MOTOR_STOP'},
+ {bit: 5, group: 'other', name: 'SERVO_TILT'},
+ {bit: 6, group: 'other', name: 'SOFTSERIAL', haveTip: true},
+ {bit: 7, group: 'gps', name: 'GPS', haveTip: true},
+ {bit: 8, group: 'rxFailsafe', name: 'FAILSAFE'},
+ {bit: 9, group: 'other', name: 'SONAR'},
+ {bit: 10, group: 'other', name: 'TELEMETRY'},
+ {bit: 11, group: 'batteryCurrent', name: 'CURRENT_METER'},
+ {bit: 12, group: 'other', name: '3D'},
+ {bit: 13, group: 'rxMode', mode: 'group', name: 'RX_PARALLEL_PWM'},
+ {bit: 14, group: 'rxMode', mode: 'group', name: 'RX_MSP'},
+ {bit: 15, group: 'rssi', name: 'RSSI_ADC'},
+ {bit: 16, group: 'other', name: 'LED_STRIP'},
+ {bit: 17, group: 'other', name: 'DISPLAY'},
+ {bit: 19, group: 'other', name: 'BLACKBOX', haveTip: true}
+ ];
+
+ if (semver.gte(config.apiVersion, "1.12.0")) {
+ features.push(
+ {bit: 20, group: 'other', name: 'CHANNEL_FORWARDING'}
+ );
+ }
+
+ if (semver.gte(config.apiVersion, "1.16.0")) {
+ features.push(
+ {bit: 21, group: 'other', name: 'TRANSPONDER', haveTip: true}
+ );
+ }
+
+ if (semver.gte(config.flightControllerVersion, "2.8.0")) {
+ features.push(
+ {bit: 22, group: 'other', name: 'AIRMODE'},
+ {bit: 23, group: 'pidTuning', name: 'SUPEREXPO_RATES'},
+ {bit: 24, group: 'other', name: 'OSD'}
+ );
+ }
+
+ this._features = features;
+}
+
+Features.prototype.isFeatureEnabled = function (featureSet, featureName) {
+ var features = this._features;
+ for (var i = 0; i < features.length; i++) {
+ if (features[i].name === featureName && bit_check(featureSet, features[i].bit)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+Features.prototype.generateElements = function (featuresElements, radioGroups) {
+ var features = this._features;
+ for (var i = 0; i < features.length; i++) {
+ var row_e;
+
+ var feature_tip_html = '';
+ if (features[i].haveTip) {
+ feature_tip_html = '
';
+ }
+
+ if (features[i].mode === 'group') {
+ row_e = $(' | | '
+ + feature_tip_html + ' |
');
+ radioGroups.push(features[i].group);
+ } else {
+ row_e = $(' | | '
+ + feature_tip_html + ' |
');
+
+ var feature_e = row_e.find('input.feature');
+
+ feature_e.prop('checked', bit_check(BF_CONFIG.features, features[i].bit));
+ feature_e.data('bit', features[i].bit);
+ }
+
+ featuresElements.each(function () {
+ if ($(this).hasClass(features[i].group)) {
+ $(this).append(row_e);
+ }
+ });
+ }
+}
+
+Features.prototype.updateData = function (featureSet, featureElement) {
+ switch (featureElement.attr('type')) {
+ case 'checkbox':
+ var bit = featureElement.data('bit');
+
+ if (featureElement.is(':checked')) {
+ featureSet = bit_set(featureSet, bit);
+ } else {
+ featureSet = bit_clear(featureSet, bit);
+ }
+
+ break;
+ case 'radio':
+ var group = featureElement.attr('name');
+ var controlElements = $('input[name="' + group + '"]');
+ var selectedBit = controlElements.filter(':checked').val();
+
+ controlElements.each(function() {
+ var bit = $(this).val();
+ if (selectedBit === bit) {
+ featureSet = bit_set(BF_CONFIG.featureSet, bit);
+ } else {
+ featureSet = bit_clear(featureSet, bit);
+ }
+
+ });
+
+ break;
+ }
+
+ return featureSet;
+}
diff --git a/js/msp.js b/js/msp.js
index 12c6cf5f..c63d60b8 100755
--- a/js/msp.js
+++ b/js/msp.js
@@ -707,6 +707,11 @@ var MSP = {
BF_CONFIG.board_align_yaw = data.getInt16(10, 1); // -180 - 360
BF_CONFIG.currentscale = data.getInt16(12, 1);
BF_CONFIG.currentoffset = data.getUint16(14, 1);
+
+ if (this.features) {
+ updateTabList(BF_CONFIG.features, this.features);
+ }
+
break;
case MSP_codes.MSP_SET_BF_CONFIG:
break;
@@ -720,8 +725,16 @@ var MSP = {
case MSP_codes.MSP_API_VERSION:
var offset = 0;
+ var apiVersion = CONFIG.apiVersion;
+
CONFIG.mspProtocolVersion = data.getUint8(offset++);
CONFIG.apiVersion = data.getUint8(offset++) + '.' + data.getUint8(offset++) + '.0';
+
+ if ((!this.features || CONFIG.apiVersion !== apiVersion)
+ && CONFIG.flightControllerVersion !== '') {
+ this.features = new Features(CONFIG);
+ }
+
break;
case MSP_codes.MSP_FC_VARIANT:
@@ -735,7 +748,16 @@ var MSP = {
case MSP_codes.MSP_FC_VERSION:
var offset = 0;
+ var flightControllerVersion = CONFIG.flightControllerVersion;
+
CONFIG.flightControllerVersion = data.getUint8(offset++) + '.' + data.getUint8(offset++) + '.' + data.getUint8(offset++);
+
+ if ((!this.features
+ || CONFIG.flightControllerVersion !== flightControllerVersion)
+ && CONFIG.apiVersion !== '') {
+ this.features = new Features(CONFIG);
+ }
+
break;
case MSP_codes.MSP_BUILD_INFO:
@@ -2072,7 +2094,7 @@ MSP.sendRxFailConfig = function(onCompleteCallback) {
}
MSP.send_message(MSP_codes.MSP_SET_RXFAIL_CONFIG, buffer, false, nextFunction);
}
-};
+}
MSP.SDCARD_STATE_NOT_PRESENT = 0;
MSP.SDCARD_STATE_FATAL = 1;
diff --git a/js/serial_backend.js b/js/serial_backend.js
index f5e507fc..e7d1825a 100755
--- a/js/serial_backend.js
+++ b/js/serial_backend.js
@@ -262,9 +262,11 @@ function onConnect() {
$('div#connectbutton a.connect_state').text(chrome.i18n.getMessage('disconnect')).addClass('active');
$('div#connectbutton a.connect').addClass('active');
$('#tabs ul.mode-disconnected').hide();
- $('#tabs ul.mode-connected').show();
+ $('#tabs ul.mode-connected-cli').show();
if (CONFIG.flightControllerVersion !== '') {
+ $('#tabs ul.mode-connected').show();
+
if (semver.gte(CONFIG.flightControllerVersion, "3.0.0")) {
MSP.send_message(MSP_codes.MSP_STATUS_EX, false, false);
} else {
@@ -301,6 +303,7 @@ function onClosed(result) {
}
$('#tabs ul.mode-connected').hide();
+ $('#tabs ul.mode-connected-cli').hide();
$('#tabs ul.mode-disconnected').show();
var sensor_state = $('#sensor-status');
diff --git a/main.css b/main.css
index 063be1c9..a08fc399 100644
--- a/main.css
+++ b/main.css
@@ -508,6 +508,10 @@ input[type="number"]::-webkit-inner-spin-button {
display: none;
}
+#tabs ul.mode-connected-cli {
+ display: none;
+}
+
#tabs li {
border-bottom: 1px solid rgba(0, 0, 0, 0.30);
}
diff --git a/main.html b/main.html
index 144df8e1..76cabecd 100755
--- a/main.html
+++ b/main.html
@@ -64,6 +64,7 @@
+
@@ -226,6 +227,8 @@
+
+