1
0
Fork 0
mirror of https://github.com/iNavFlight/inav-configurator.git synced 2025-07-19 14:25:13 +03:00

Merge branch 'master' of https://github.com/iNavFlight/inav-configurator into mission-planer

Fix conflicts:
 _locales/en/messages.json
This commit is contained in:
afinogen 2018-01-29 13:55:20 +03:00
commit db31180753
17 changed files with 466 additions and 128 deletions

View file

@ -735,6 +735,15 @@
"configurationSPIProtocol": {
"message": "RX SPI protocol"
},
"configurationPersonalization": {
"message": "Personalization"
},
"configurationCraftName": {
"message": "Craft Name"
},
"configurationCraftNameHelp": {
"message": "Craft name. Can be displayed by OSD and by compatible RC systems."
},
"configurationEepromSaved": {
"message": "EEPROM <span style=\"color: #37a8db\">saved</span>"
},
@ -1130,10 +1139,6 @@
"transponderEepromSaved": {
"message": "EEPROM <span style=\"color: #37a8db\">saved</span>"
},
"servosFirmwareUpgradeRequired": {
"message": "Servos requires firmware &gt;= 1.10.0. and target support."
},
"servosChangeDirection": {
"message": "Change Direction in TX To Match"
},
@ -2320,6 +2325,7 @@
"downloadUpdatesBtn": {
"message": "Download new app"
},
<<<<<<< HEAD
"tabMissionControl": {
"message": "Mission Control"
},
@ -2358,5 +2364,14 @@
},
"confirm_delete_all_points": {
"message": "Do you really want to delete all points?"
},
"servoMixer": {
"message": "Servo mixer"
},
"servoMixerDelete": {
"message": "Delete"
},
"servoMixerAdd": {
"message": "Add new mixer rule"
}
}

View file

@ -90,6 +90,8 @@ sources.js = [
'./js/localization.js',
'./js/boards.js',
'./js/tasks.js',
'./js/servoMixRule.js',
'./js/servoMixRuleCollection.js',
'./main.js',
'./tabs/*.js',
'./js/eventFrequencyAnalyzer.js',

View file

@ -151,7 +151,7 @@ var FC = {
ADJUSTMENT_RANGES = [];
SERVO_CONFIG = [];
SERVO_RULES = [];
SERVO_RULES = new ServoMixRuleCollection();
SERIAL_CONFIG = {
ports: [],
@ -950,5 +950,27 @@ var FC = {
},
getRcMapLetters: function () {
return ['A', 'E', 'R', 'T', '5', '6', '7', '8'];
},
getServoMixInputNames: function () {
return [
'Stabilised Roll',
'Stabilised Pitch',
'Stabilised Yaw',
'Stabilised Throttle',
'RC Roll',
'RC Pitch',
'RC Yaw',
'RC Throttle',
'RC Channel 5',
'RC Channel 6',
'RC Channel 7',
'RC Channel 8',
'Gimbal Pitch',
'Gimbal Roll',
'Flaps'
];
},
getServoMixInputName: function (input) {
return getServoMixInputNames()[input];
}
};

View file

@ -2,29 +2,29 @@
// generate mixer
var mixerList = [
{name: 'Tricopter', model: 'tricopter', image: 'tri'}, // 1
{name: 'Quad +', model: 'quad_x', image: 'quad_p'}, // 2
{name: 'Quad X', model: 'quad_x', image: 'quad_x'}, // 3
{name: 'Bicopter', model: 'custom', image: 'bicopter'}, // 4
{name: 'Gimbal', model: 'custom', image: 'custom'}, // 5
{name: 'Y6', model: 'y6', image: 'y6'}, // 6
{name: 'Hex +', model: 'hex_plus', image: 'hex_p'}, // 7
{name: 'Flying Wing', model: 'custom', image: 'flying_wing'}, // 8
{name: 'Y4', model: 'y4', image: 'y4'}, // 9
{name: 'Hex X', model: 'hex_x', image: 'hex_x'}, // 10
{name: 'Octo X8', model: 'custom', image: 'octo_x8'}, // 11
{name: 'Octo Flat +', model: 'custom', image: 'octo_flat_p'}, // 12
{name: 'Octo Flat X', model: 'custom', image: 'octo_flat_x'}, // 13
{name: 'Airplane', model: 'custom', image: 'airplane'}, // 14
{name: 'Heli 120', model: 'custom', image: 'custom'}, // 15
{name: 'Heli 90', model: 'custom', image: 'custom'}, // 16
{name: 'V-tail Quad', model: 'quad_vtail', image: 'vtail_quad'}, // 17
{name: 'Hex H', model: 'custom', image: 'custom'}, // 18
{name: 'PPM to SERVO', model: 'custom', image: 'custom'}, // 19
{name: 'Dualcopter', model: 'custom', image: 'custom'}, // 20
{name: 'Singlecopter', model: 'custom', image: 'custom'}, // 21
{name: 'A-tail Quad', model: 'quad_atail', image: 'atail_quad'}, // 22
{name: 'Custom', model: 'custom', image: 'custom'}, // 23
{name: 'Custom Airplane', model: 'custom', image: 'custom'}, // 24
{name: 'Custom Tricopter', model: 'custom', image: 'custom'} // 25
{name: 'Tricopter', model: 'tricopter', image: 'tri', hasCustomServoMixer: false}, // 1
{name: 'Quad +', model: 'quad_x', image: 'quad_p', hasCustomServoMixer: false}, // 2
{name: 'Quad X', model: 'quad_x', image: 'quad_x', hasCustomServoMixer: false}, // 3
{name: 'Bicopter', model: 'custom', image: 'bicopter', hasCustomServoMixer: false}, // 4
{name: 'Gimbal', model: 'custom', image: 'custom', hasCustomServoMixer: false}, // 5
{name: 'Y6', model: 'y6', image: 'y6', hasCustomServoMixer: false}, // 6
{name: 'Hex +', model: 'hex_plus', image: 'hex_p', hasCustomServoMixer: false}, // 7
{name: 'Flying Wing', model: 'custom', image: 'flying_wing', hasCustomServoMixer: false}, // 8
{name: 'Y4', model: 'y4', image: 'y4', hasCustomServoMixer: false}, // 9
{name: 'Hex X', model: 'hex_x', image: 'hex_x', hasCustomServoMixer: false}, // 10
{name: 'Octo X8', model: 'custom', image: 'octo_x8', hasCustomServoMixer: false}, // 11
{name: 'Octo Flat +', model: 'custom', image: 'octo_flat_p', hasCustomServoMixer: false}, // 12
{name: 'Octo Flat X', model: 'custom', image: 'octo_flat_x', hasCustomServoMixer: false}, // 13
{name: 'Airplane', model: 'custom', image: 'airplane', hasCustomServoMixer: false}, // 14
{name: 'Heli 120', model: 'custom', image: 'custom', hasCustomServoMixer: false}, // 15
{name: 'Heli 90', model: 'custom', image: 'custom', hasCustomServoMixer: false}, // 16
{name: 'V-tail Quad', model: 'quad_vtail', image: 'vtail_quad', hasCustomServoMixer: false}, // 17
{name: 'Hex H', model: 'custom', image: 'custom', hasCustomServoMixer: false}, // 18
{name: 'PPM to SERVO', model: 'custom', image: 'custom', hasCustomServoMixer: false}, // 19
{name: 'Dualcopter', model: 'custom', image: 'custom', hasCustomServoMixer: false}, // 20
{name: 'Singlecopter', model: 'custom', image: 'custom', hasCustomServoMixer: false}, // 21
{name: 'A-tail Quad', model: 'quad_atail', image: 'atail_quad', hasCustomServoMixer: false}, // 22
{name: 'Custom', model: 'custom', image: 'custom', hasCustomServoMixer: true}, // 23
{name: 'Custom Airplane', model: 'custom', image: 'custom', hasCustomServoMixer: true}, // 24
{name: 'Custom Tricopter', model: 'custom', image: 'custom', hasCustomServoMixer: true} // 25
];

View file

@ -10,6 +10,9 @@ var MSPCodes = {
MSP_INAV_PID: 6,
MSP_SET_INAV_PID: 7,
MSP_NAME: 10,
MSP_SET_NAME: 11,
MSP_NAV_POSHOLD: 12,
MSP_SET_NAV_POSHOLD: 13,
MSP_CALIBRATION_DATA: 14,

View file

@ -355,6 +355,20 @@ var mspHelper = (function (gui) {
}
break;
case MSPCodes.MSP_SERVO_MIX_RULES:
SERVO_RULES.flush();
if (data.byteLength % 7 === 0) {
for (i = 0; i < data.byteLength; i += 7) {
SERVO_RULES.put(new ServoMixRule(
data.getInt8(i + 0, true),
data.getInt8(i + 1, true),
data.getInt8(i + 2, true),
data.getInt8(i + 3, true)
));
}
}
SERVO_RULES.cleanup();
break;
case MSPCodes.MSP_SERVO_CONFIGURATIONS:
@ -1106,6 +1120,11 @@ var mspHelper = (function (gui) {
case MSPCodes.MSP_OSD_CHAR_WRITE:
console.log('OSD char uploaded');
break;
case MSPCodes.MSP_NAME:
break;
case MSPCodes.MSP_SET_NAME:
console.log("Craft name set");
break;
case MSPCodes.MSPV2_SETTING:
break;
case MSPCodes.MSPV2_SET_SETTING:
@ -1693,7 +1712,6 @@ var mspHelper = (function (gui) {
nextFunction();
}
function send_next_servo_configuration() {
var buffer = [];
@ -1736,24 +1754,41 @@ var mspHelper = (function (gui) {
}
MSP.send_message(MSPCodes.MSP_SET_SERVO_CONFIGURATION, buffer, false, nextFunction);
}
};
//FIXME looks like this is not used and not ever implemented
//noinspection JSUnusedLocalSymbols
function send_channel_forwarding() {
self.sendServoMixer = function (onCompleteCallback) {
var nextFunction = sendMixer,
servoIndex = 0;
if (SERVO_RULES.length == 0) {
onCompleteCallback();
} else {
nextFunction();
}
function sendMixer() {
var buffer = [];
for (var i = 0; i < SERVO_CONFIG.length; i++) {
var out = SERVO_CONFIG[i].indexOfChannelToForward;
if (out == undefined) {
out = 255; // Cleanflight defines "CHANNEL_FORWARDING_DISABLED" as "(uint8_t)0xFF"
}
buffer.push(out);
}
// send one at a time, with index
var servoRule = SERVO_RULES.get()[servoIndex];
buffer.push(servoIndex);
buffer.push(servoRule.getTarget());
buffer.push(servoRule.getInput());
buffer.push(servoRule.getRate());
buffer.push(servoRule.getSpeed());
buffer.push(0);
buffer.push(0);
buffer.push(0);
// prepare for next iteration
servoIndex++;
if (servoIndex == 16) { //This is the last rule. Not pretty, but we have to send all rules
nextFunction = onCompleteCallback;
MSP.send_message(MSPCodes.MSP_SET_CHANNEL_FORWARDING, buffer, false, nextFunction);
}
MSP.send_message(MSPCodes.MSP_SET_SERVO_MIX_RULE, buffer, false, nextFunction);
}
};
@ -2548,5 +2583,46 @@ var mspHelper = (function (gui) {
}
};
self.loadServoConfiguration = function (callback) {
MSP.send_message(MSPCodes.MSP_SERVO_CONFIGURATIONS, false, false, callback);
};
self.loadServoMixRules = function (callback) {
MSP.send_message(MSPCodes.MSP_SERVO_MIX_RULES, false, false, callback);
}
self.getCraftName = function(callback) {
if (semver.gt(CONFIG.flightControllerVersion, "1.8.0")) {
MSP.send_message(MSPCodes.MSP_NAME, false, false, function(resp) {
var name = "";
for (var ii = 0; ii < resp.data.byteLength; ii++) {
var c = resp.data.readU8();
if (c != 0) {
name += String.fromCharCode(c);
}
}
if (callback) {
callback(name);
}
});
} else if (callback) {
callback(null);
}
};
self.setCraftName = function(name, callback) {
if (semver.gt(CONFIG.flightControllerVersion, "1.8.0")) {
var data = [];
name = name || "";
for (var ii = 0; ii < name.length; ii++) {
data.push(name.charCodeAt(ii));
}
MSP.send_message(MSPCodes.MSP_SET_NAME, data, false, callback);
} else if (callback) {
callback();
}
};
return self;
})(GUI);

View file

@ -9,7 +9,7 @@ var MSPChainerClass = function () {
self.exitPoint = null;
self.chainIndex = 0;
self.setChain = function(chain) {
self.setChain = function (chain) {
self.chain = chain;
};
@ -21,12 +21,12 @@ var MSPChainerClass = function () {
self.chainIndex++;
if (self.chain[self.chainIndex]) {
self.chain[self.chainIndex](self.returnCallback);
} else {
} else if (self.exitPoint) {
self.exitPoint();
}
};
self.execute = function() {
self.execute = function () {
self.chainIndex = 0;
self.chain[self.chainIndex](self.returnCallback);
};

45
js/servoMixRule.js Normal file
View file

@ -0,0 +1,45 @@
/*global $*/
'use strict';
var ServoMixRule = function (target, input, rate, speed) {
var self = {};
self.getTarget = function () {
return target;
};
self.setTarget = function (data) {
target = data;
};
self.getInput = function () {
return input;
};
self.setInput = function (data) {
input = data;
};
self.getRate = function () {
return rate;
};
self.setRate = function (data) {
rate = data;
};
self.getSpeed = function () {
return speed;
};
self.setSpeed = function (data) {
speed = data;
};
self.isUsed = function () {
return rate !== 0;
};
return self;
};

View file

@ -0,0 +1,49 @@
/*global $, ServoMixRule*/
'use strict';
var ServoMixRuleCollection = function () {
var self = {};
var data = [];
self.put = function (element) {
data.push(element);
};
self.get = function () {
return data;
};
self.drop = function (index) {
data[index].setRate(0);
self.cleanup();
};
self.flush = function () {
data = [];
};
self.cleanup = function () {
var tmpData = [];
data.forEach(function (element) {
if (element.isUsed()) {
tmpData.push(element);
}
});
data = tmpData;
};
self.inflate = function () {
while (self.hasFreeSlots()) {
self.put(new ServoMixRule(0, 0, 0, 0));
}
}
self.hasFreeSlots = function () {
return data.length < 16;
};
return self;
};

View file

@ -1326,6 +1326,15 @@ dialog {
float: left;
}
.default_btn.narrow {
width: auto;
margin-bottom: 0;
}
.default_btn.narrow a {
padding: 5px;
}
.default_btn a {
padding: 5px 0 5px 0;
text-align: center;

View file

@ -20,9 +20,8 @@
font-weight: bold;
}
.config-section .number input,
.tab-configuration .number input {
width: 65px;
.config-section input,
.tab-configuration input {
padding-left: 3px;
height: 20px;
line-height: 20px;
@ -34,8 +33,17 @@
font-weight: normal;
}
.tab-configuration .number .disabled {
.config-section .number input,
.tab-configuration .number input {
width: 65px;
}
.config-section .string input,
.tab-configuration .string input {
width: 130px;
}
.tab-configuration .disabled {
background-color: #ececec;
}
@ -226,6 +234,10 @@ hr {
left: 2em;
}
.config-section .string label {
left: 175px;
}
.config-section .radio input {
margin-top: 3px;
margin-left: 5px;

View file

@ -50,7 +50,16 @@
background-color: #f9f9f9;
}
.tab-servos table tr:first-child {
#servo-mix-table input {
width: 75px;
}
#servo-mix-table .btn {
float: none;
}
#servo-config-table tr:first-child,
#servo-mix-table thead tr {
border-left: 1px solid #e4e4e4;
border-right: 1px solid #e4e4e4;
background-color: #828885;
@ -154,22 +163,6 @@
bottom: 10px;
}
.tab-servos .require-support {
display: none;
}
.tab-servos.supported .require-support {
display: block;
}
.tab-servos .require-upgrade {
display: block;
}
.tab-servos.supported .require-upgrade {
display: none;
}
.tab-servos .live span {
margin-right: 10px;
}

View file

@ -212,6 +212,21 @@
</div>
</div>
<div class="config-section gui_box grey config-personalization">
<div class="gui_box_titlebar">
<div class="spacer_box_title" data-i18n="configurationPersonalization"></div>
</div>
<div class="spacer_box">
<div class="string">
<input maxlength="16" id="craft_name" name="craft_name" />
<label for="craft_name">
<span data-i18n="configurationCraftName"></span>
</label>
<div class="helpicon cf_tip" data-i18n_title="configurationCraftNameHelp"></div>
</div>
</div>
</div>
</div>
<!--Right column begins here-->

View file

@ -10,6 +10,18 @@ TABS.configuration.initialize = function (callback, scrollPosition) {
googleAnalytics.sendAppView('Configuration');
}
var craftName = null;
var loadCraftName = function(callback) {
mspHelper.getCraftName(function(name) {
craftName = name;
callback();
});
};
var saveCraftName = function(callback) {
mspHelper.setCraftName(craftName, callback);
};
var loadChainer = new MSPChainerClass();
loadChainer.setChain([
@ -22,7 +34,8 @@ TABS.configuration.initialize = function (callback, scrollPosition) {
mspHelper.loadSensorAlignment,
mspHelper.loadAdvancedConfig,
mspHelper.loadINAVPidConfig,
mspHelper.loadSensorConfig
mspHelper.loadSensorConfig,
loadCraftName
]);
loadChainer.setExitPoint(load_html);
loadChainer.execute();
@ -41,6 +54,7 @@ TABS.configuration.initialize = function (callback, scrollPosition) {
mspHelper.saveAdvancedConfig,
mspHelper.saveINAVPidConfig,
mspHelper.saveSensorConfig,
saveCraftName,
mspHelper.saveToEeprom
]);
saveChainer.setExitPoint(reboot);
@ -597,6 +611,14 @@ TABS.configuration.initialize = function (callback, scrollPosition) {
});
});
// Craft name
if (craftName != null) {
$('.config-personalization').show();
$('input[name="craft_name"]').val(craftName);
} else {
// craft name not supported by the firmware
$('.config-personalization').hide();
}
$('a.save').click(function () {
// gather data that doesn't have automatic change event bound
@ -635,6 +657,8 @@ TABS.configuration.initialize = function (callback, scrollPosition) {
SENSOR_ALIGNMENT.align_acc = parseInt(orientation_acc_e.val());
SENSOR_ALIGNMENT.align_mag = parseInt(orientation_mag_e.val());
craftName = $('input[name="craft_name"]').val();
var rxTypes = FC.getRxTypes();
function is_using_rx_type(name) {

View file

@ -421,7 +421,7 @@ OSD.constants = {
{
name: 'FLYMODE',
id: 7,
preview: 'STAB'
preview: 'ACRO'
},
{
name: 'MESSAGES',

View file

@ -1,13 +1,12 @@
<!--suppress HtmlFormInputWithoutLabel -->
<div class="tab-servos toolbar_fixed_bottom">
<div class="content_wrapper">
<div class="tab_title" data-i18n="tabServos">Servos</div>
<div class="cf_doc_version_bt">
<a id="button-documentation" href="" target="_blank"></a>
</div>
<div class="require-support">
<div>
<div class="title" data-i18n="servosChangeDirection"></div>
<table class="fields">
<table id="servo-config-table" class="fields">
<tr class="main">
<th width="110px" data-i18n="servosName"></th>
<th data-i18n="servosMid"></th>
@ -23,9 +22,28 @@
<input type="checkbox" class="togglemedium" /> <span data-i18n="servosLiveMode"></span>
</div>
</div>
<div class="note require-upgrade">
<div class="note_spacer">
<p data-i18n="servosFirmwareUpgradeRequired"></p>
<div class="clear-both"></div>
<div id="servo-mix-table-wrapper" class="margin-top">
<div class="tab_title" data-i18n="servoMixer">Servo mixer</div>
<div class="btn default_btn narrow pull-right" style="margin-bottom: 15px">
<a href="#" data-role="role-add" data-i18n="servoMixerAdd"></a>
</div>
<table id="servo-mix-table">
<thead>
<tr>
<th style="width: 75px">Servo</th>
<th>Input</th>
<th>Weight</th>
<th>Speed</th>
<th style="width: 75px"></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div class="btn default_btn narrow pull-right" style="margin-bottom: 15px">
<a href="#" data-role="role-add" data-i18n="servoMixerAdd"></a>
</div>
</div>
</div>

View file

@ -9,44 +9,102 @@ TABS.servos.initialize = function (callback) {
googleAnalytics.sendAppView('Servos');
}
function get_servo_configurations() {
MSP.send_message(MSPCodes.MSP_SERVO_CONFIGURATIONS, false, false, get_servo_mix_rules);
}
var loadChainer = new MSPChainerClass();
function get_servo_mix_rules() {
MSP.send_message(MSPCodes.MSP_SERVO_MIX_RULES, false, false, get_rc_data);
}
loadChainer.setChain([
mspHelper.loadServoConfiguration,
mspHelper.loadRcData,
mspHelper.loadBfConfig,
mspHelper.loadServoMixRules
]);
loadChainer.setExitPoint(load_html);
loadChainer.execute();
function get_rc_data() {
MSP.send_message(MSPCodes.MSP_RC, false, false, get_boxnames_data);
}
var saveChainer = new MSPChainerClass();
function get_boxnames_data() {
MSP.send_message(MSPCodes.MSP_BOXNAMES, false, false, load_html);
}
saveChainer.setChain([
mspHelper.sendServoConfigurations,
mspHelper.sendServoMixer,
mspHelper.saveToEeprom
]);
saveChainer.setExitPoint(function () {
GUI.log(chrome.i18n.getMessage('servosEepromSave'));
SERVO_RULES.cleanup();
renderServoMixRules();
});
function load_html() {
$('#content').load("./tabs/servos.html", process_html);
}
get_servo_configurations();
function renderServoMixRules() {
var $servoMixTable = $('#servo-mix-table'),
$servoMixTableBody = $servoMixTable.find('tbody');
/*
* Process servo mix table UI
*/
var rules = SERVO_RULES.get();
$servoMixTableBody.find("*").remove();
for (servoRuleIndex in rules) {
if (rules.hasOwnProperty(servoRuleIndex)) {
const servoRule = rules[servoRuleIndex];
$servoMixTableBody.append('\
<tr>\
<td><input type="number" class="mix-rule-servo" step="1" min="0" max="7" /></td>\
<td><select class="mix-rule-input"></select></td>\
<td><input type="number" class="mix-rule-rate" step="1" min="-100" max="100" /></td>\
<td><input type="number" class="mix-rule-speed" step="1" min="0" max="255" /></td>\
<td><span class="btn default_btn narrow"><a href="#" data-role="role-delete" data-i18n="servoMixerDelete"></a></span></td>\
</tr>\
');
const $row = $servoMixTableBody.find('tr:last');
GUI.fillSelect($row.find(".mix-rule-input"), FC.getServoMixInputNames(), servoRule.getInput());
$row.find(".mix-rule-input").val(servoRule.getInput()).change(function () {
servoRule.setInput($(this).val());
});
$row.find(".mix-rule-servo").val(servoRule.getTarget()).change(function () {
servoRule.setTarget($(this).val());
});
$row.find(".mix-rule-rate").val(servoRule.getRate()).change(function () {
servoRule.setRate($(this).val());
});
$row.find(".mix-rule-speed").val(servoRule.getSpeed()).change(function () {
servoRule.setSpeed($(this).val());
});
$row.find("[data-role='role-delete']").attr("data-index", servoRuleIndex);
}
}
localize();
}
function update_ui() {
var i,
$tabServos = $(".tab-servos");
$tabServos = $(".tab-servos"),
$servoConfigTable = $('#servo-config-table'),
$servoMixTable = $('#servo-mix-table'),
$servoMixTableBody = $servoMixTable.find('tbody');
if (SERVO_CONFIG.length == 0) {
$tabServos.removeClass("supported");
$tabServos.addClass("is-hidden");
return;
}
$tabServos.addClass("supported");
var servoCheckbox = '';
var servoHeader = '';
for (i = 0; i < RC.active_channels-4; i++) {
servoHeader = servoHeader + '<th class="short">CH' + (i+5) + '</th>';
for (i = 0; i < RC.active_channels - 4; i++) {
servoHeader = servoHeader + '<th class="short">CH' + (i + 5) + '</th>';
}
servoHeader = servoHeader + '<th data-i18n="servosDirectionAndRate"></th>';
@ -54,18 +112,16 @@ TABS.servos.initialize = function (callback) {
servoCheckbox = servoCheckbox + '<td class="channel"><input type="checkbox"/></td>';
}
$('div.tab-servos table.fields tr.main').append(servoHeader);
$servoConfigTable.find('tr.main').append(servoHeader);
function process_servos(name, alternate, obj) {
$('div.supported_wrapper').show();
$('div.tab-servos table.fields').append('\
$servoConfigTable.append('\
<tr> \
<td style="text-align: center">' + name + '</td>\
<td class="middle"><input type="number" min="500" max="2500" value="' + SERVO_CONFIG[obj].middle + '" /></td>\
<td class="min"><input type="number" min="500" max="2500" value="' + SERVO_CONFIG[obj].min +'" /></td>\
<td class="max"><input type="number" min="500" max="2500" value="' + SERVO_CONFIG[obj].max +'" /></td>\
<td class="min"><input type="number" min="500" max="2500" value="' + SERVO_CONFIG[obj].min + '" /></td>\
<td class="max"><input type="number" min="500" max="2500" value="' + SERVO_CONFIG[obj].max + '" /></td>\
' + servoCheckbox + '\
<td class="direction">\
</td>\
@ -73,13 +129,13 @@ TABS.servos.initialize = function (callback) {
');
if (SERVO_CONFIG[obj].indexOfChannelToForward >= 0) {
$('div.tab-servos table.fields tr:last td.channel input').eq(SERVO_CONFIG[obj].indexOfChannelToForward).prop('checked', true);
$servoConfigTable.find('tr:last td.channel input').eq(SERVO_CONFIG[obj].indexOfChannelToForward).prop('checked', true);
}
// adding select box and generating options
$('div.tab-servos table.fields tr:last td.direction').append('<select class="rate" name="rate"></select>');
$servoConfigTable.find('tr:last td.direction').append('<select class="rate" name="rate"></select>');
var select = $('div.tab-servos table.fields tr:last td.direction select');
var select = $servoConfigTable.find('tr:last td.direction select');
for (var i = FC.MAX_SERVO_RATE; i >= FC.MIN_SERVO_RATE; i--) {
select.append('<option value="' + i + '">Rate: ' + i + '%</option>');
@ -88,20 +144,20 @@ TABS.servos.initialize = function (callback) {
// select current rate
select.val(SERVO_CONFIG[obj].rate);
$('div.tab-servos table.fields tr:last').data('info', {'obj': obj});
$servoConfigTable.find('tr:last').data('info', { 'obj': obj });
// UI hooks
// only one checkbox for indicating a channel to forward can be selected at a time, perhaps a radio group would be best here.
$('div.tab-servos table.fields tr:last td.channel input').click(function () {
if($(this).is(':checked')) {
$servoConfigTable.find('tr:last td.channel input').click(function () {
if ($(this).is(':checked')) {
$(this).parent().parent().find('.channel input').not($(this)).prop('checked', false);
}
});
}
function servos_update(save_configuration_to_eeprom) {
$('div.tab-servos table.fields tr:not(".main")').each(function () {
$servoConfigTable.find('tr:not(".main")').each(function () {
var info = $(this).data('info');
@ -113,42 +169,28 @@ TABS.servos.initialize = function (callback) {
SERVO_CONFIG[info.obj].indexOfChannelToForward = channelIndex;
SERVO_CONFIG[info.obj].middle = parseInt($('.middle input', this).val());
SERVO_CONFIG[info.obj].min = parseInt($('.min input', this).val());
SERVO_CONFIG[info.obj].max = parseInt($('.max input', this).val());
SERVO_CONFIG[info.obj].rate = parseInt($('.direction select', this).val());
});
//
// send data to FC
//
//FIXME investigate why the same frame is sent twice
mspHelper.sendServoConfigurations(send_servo_mixer_rules);
function send_servo_mixer_rules() {
mspHelper.sendServoConfigurations(save_to_eeprom);
}
function save_to_eeprom() {
if (save_configuration_to_eeprom) {
MSP.send_message(MSPCodes.MSP_EEPROM_WRITE, false, false, function () {
GUI.log(chrome.i18n.getMessage('servosEepromSave'));
});
}
}
//Save configuration to FC
SERVO_RULES.cleanup();
SERVO_RULES.inflate();
saveChainer.execute();
}
// drop previous table
$('div.tab-servos table.fields tr:not(:first)').remove();
$servoConfigTable.find('tr:not(:first)').remove();
for (var servoIndex = 0; servoIndex < 8; servoIndex++) {
process_servos('Servo ' + servoIndex, '', servoIndex, false);
}
// UI hooks for dynamically generated elements
$('table.directions select, table.directions input, table.fields select, table.fields input').change(function () {
$('table.directions select, table.directions input, #servo-config-table select, #servo-config-table input').change(function () {
if ($('div.live input').is(':checked')) {
// apply small delay as there seems to be some funky update business going wrong
helper.timeout.add('servos_update', servos_update, 10);
@ -159,6 +201,19 @@ TABS.servos.initialize = function (callback) {
servos_update(true);
});
$servoMixTableBody.on('click', "[data-role='role-delete']", function (event) {
SERVO_RULES.drop($(event.currentTarget).attr("data-index"));
renderServoMixRules();
});
$("[data-role='role-add']").click(function () {
if (SERVO_RULES.hasFreeSlots()) {
SERVO_RULES.put(new ServoMixRule(0, 0, 0, 0));
renderServoMixRules();
}
});
renderServoMixRules();
}
function process_html() {