Added new timer elements and stats

Adds array length checking on configurator side

(old timers on stats can simply be replaced as the MSP API version has
ot changed since they were first added)
10.3.x-maintenance
Dan Nixon 2017-06-29 10:44:48 +01:00
parent 736c6c293c
commit 829b0b468a
4 changed files with 242 additions and 21 deletions

View File

@ -2305,6 +2305,12 @@
"osdDescElementCompassBar": {
"message": "Graphical compass bar showing current heading"
},
"osdDescElementTimer1" : {
"message": "Shows the value of timer 1"
},
"osdDescElementTimer2" : {
"message": "Shows the value of timer 2"
},
"osdDescStatMaxSpeed": {
"message": "Maximum recorded speed"
@ -2342,6 +2348,22 @@
"osdDescStatBlackboxLogNumber": {
"message": "Log number for this flights Blackbox log"
},
"osdDescStatTimer1": {
"message": "Value of timer 1 at time of disarming"
},
"osdDescStatTimer2": {
"message": "Value of timer 2 at time of disarming"
},
"osdTimerSourceTooltip": {
"message": "Select the timer source, this controls the duration/event that the timer measures"
},
"osdTimerPrecisionTooltip": {
"message": "Select the timer precision, this controls to what precision the time is reported in"
},
"osdTimerAlarmTooltip": {
"message": "Select the timer alarm threshold in minutes, when the time exceeds this value the OSD element will blink, setting this to 0 disables the alarm"
},
"mainHelpArmed": {
"message": "Motor Arming"

View File

@ -375,12 +375,10 @@ button {
padding:2px;
margin-top: -2px;
display: none;
}
.tab-osd .switchable-field label {
margin-left: 5px;
}
.tab-osd .switchable-fields {
@ -388,7 +386,6 @@ button {
margin-top: 5px;
margin-bottom: 8px;
width: 100%;
}
.spacer_box_title span {
@ -450,8 +447,12 @@ button {
font-weight: normal;
}
.timer-option {
float: none !important;
padding: 2px;
margin-left: 10px;
display: inline !important;
}
@media only screen and (max-width: 1055px) , only screen and (max-device-width: 1055px) {
.tab-osd .content_wrapper {

View File

@ -61,6 +61,17 @@
<div class="units"></div>
</div>
</div>
<div class="gui_box grey timers-container requires-osd-feature" style="display:none;">
<div class="gui_box_titlebar"
style="margin-bottom: 0px;">
<div class="spacer_box_title">
Timers
</div>
</div>
<div class="spacer_box">
<div id="timer-fields" class="switchable-fields"></div>
</div>
</div>
<div class="gui_box grey alarms-container requires-osd-feature" style="display:none;">
<div class="gui_box_titlebar">
<div class="spacer_box_title">
@ -75,7 +86,7 @@
<div class="gui_box_titlebar"
style="margin-bottom: 0px;">
<div class="spacer_box_title">
Post Flight Status
Post Flight Statistics
</div>
</div>
<div class="spacer_box">

View File

@ -223,6 +223,7 @@ OSD.initData = function() {
alarms: [],
stat_items: [],
display_items: [],
timers: [],
last_positions: {},
preview_logo: true,
preview: [],
@ -231,6 +232,28 @@ OSD.initData = function() {
};
OSD.initData();
OSD.generateTimerPreview = function(osd_data, timer_index) {
var preview = '';
switch (osd_data.timers[timer_index].src) {
case 0:
preview += FONT.symbol(SYM.ON_M);
break;
case 1:
case 2:
preview += FONT.symbol(SYM.FLY_M);
break;
}
switch (osd_data.timers[timer_index].precision) {
case 0:
preview += '00:00';
break;
case 1:
preview += '00:00.00';
break;
}
return preview;
};
OSD.constants = {
VISIBLE: 0x0800,
VIDEO_TYPES: [
@ -250,6 +273,15 @@ OSD.constants = {
'IMPERIAL',
'METRIC'
],
TIMER_TYPES: [
'ON TIME',
'TOTAL ARMED TIME',
'LAST ARMED TIME'
],
TIMER_PRECISION: [
'SECOND',
'HUNDREDTH'
],
AHISIDEBARWIDTHPOSITION: 7,
AHISIDEBARHEIGHTPOSITION: 3,
@ -556,7 +588,25 @@ OSD.constants = {
default_position: -1,
positionable: true,
preview: '226000'
}
},
TIMER_1: {
name: 'TIMER_1',
desc: 'osdDescElementTimer1',
default_position: -1,
positionable: true,
preview: function(osd_data) {
return OSD.generateTimerPreview(osd_data, 0);
}
},
TIMER_2: {
name: 'TIMER_2',
desc: 'osdDescElementTimer2',
default_position: -1,
positionable: true,
preview: function(osd_data) {
return OSD.generateTimerPreview(osd_data, 1);
}
},
},
ALL_STATISTIC_FIELDS: {
MAX_SPEED: {
@ -606,6 +656,14 @@ OSD.constants = {
BLACKBOX_LOG_NUMBER: {
name: 'BLACKBOX_LOG_NUMBER',
desc: 'osdDescStatBlackboxLogNumber'
},
TIMER_1: {
name: 'TIMER_1',
desc: 'osdDescStatTimer1'
},
TIMER_2: {
name: 'TIMER_2',
desc: 'osdDescStatTimer2'
}
}
};
@ -620,9 +678,22 @@ OSD.chooseFields = function () {
F.MAIN_BATT_VOLTAGE,
F.CROSSHAIRS,
F.ARTIFICIAL_HORIZON,
F.HORIZON_SIDEBARS,
F.ONTIME,
F.FLYTIME,
F.HORIZON_SIDEBARS
];
if (semver.lt(CONFIG.apiVersion, "1.36.0")) {
OSD.constants.DISPLAY_FIELDS = OSD.constants.DISPLAY_FIELDS.concat([
F.ONTIME,
F.FLYTIME
]);
} else {
OSD.constants.DISPLAY_FIELDS = OSD.constants.DISPLAY_FIELDS.concat([
F.TIMER_1,
F.TIMER_2
]);
}
OSD.constants.DISPLAY_FIELDS = OSD.constants.DISPLAY_FIELDS.concat([
F.FLYMODE,
F.CRAFT_NAME,
F.THROTTLE_POSITION,
@ -632,7 +703,7 @@ OSD.chooseFields = function () {
F.GPS_SPEED,
F.GPS_SATS,
F.ALTITUDE
];
]);
if (semver.gte(CONFIG.apiVersion, "1.31.0")) {
OSD.constants.DISPLAY_FIELDS = OSD.constants.DISPLAY_FIELDS.concat([
F.PID_ROLL,
@ -660,7 +731,6 @@ OSD.chooseFields = function () {
if (semver.gte(CONFIG.apiVersion, "1.36.0")) {
OSD.constants.DISPLAY_FIELDS = OSD.constants.DISPLAY_FIELDS.concat([
F.MAIN_BATT_USAGE,
F.ARMED_TIME,
F.DISARMED,
F.HOME_DIR,
F.HOME_DIST,
@ -709,8 +779,8 @@ OSD.chooseFields = function () {
F.MAX_ALTITUDE,
F.BLACKBOX,
F.END_BATTERY,
F.FLYTIME,
F.ARMEDTIME,
F.TIMER_1,
F.TIMER_2,
F.MAX_DISTANCE,
F.BLACKBOX_LOG_NUMBER
];
@ -753,6 +823,14 @@ OSD.msp = {
display_item.isVisible = bits !== -1;
}
return display_item;
},
timer: function(bits, c) {
var timer = {
src: bits & 0x0F,
precision: (bits >> 4) & 0x0F,
alarm: (bits >> 8) & 0xFF
};
return timer;
}
},
pack: {
@ -764,6 +842,9 @@ OSD.msp = {
} else {
return isVisible ? (position == -1 ? 0 : position): -1;
}
},
timer: function(timer) {
return (timer.src & 0x0F) | ((timer.precision & 0x0F) << 4) | ((timer.alarm & 0xFF ) << 8);
}
}
},
@ -774,7 +855,12 @@ OSD.msp = {
// watch out, order matters! match the firmware
result.push8(OSD.data.alarms.rssi.value);
result.push16(OSD.data.alarms.cap.value);
result.push16(OSD.data.alarms.time.value);
if (semver.lt(CONFIG.apiVersion, "1.36.0")) {
result.push16(OSD.data.alarms.time.value);
} else {
// This value is unused by the firmware with configurable timers
result.push16(0);
}
result.push16(OSD.data.alarms.alt.value);
}
return result;
@ -792,12 +878,17 @@ OSD.msp = {
buffer.push8(0);
return buffer;
},
encodeTimer: function(timer) {
var buffer = [-2, timer.index];
buffer.push16(this.helpers.pack.timer(timer));
return buffer;
},
// Currently only parses MSP_MAX_OSD responses, add a switch on payload.code if more codes are handled
decode: function(payload) {
var view = payload.data;
var d = OSD.data;
d.flags = view.readU8();
if (d.flags > 0) {
if (payload.length > 1) {
d.video_system = view.readU8();
@ -806,20 +897,26 @@ OSD.msp = {
d.alarms = {};
d.alarms['rssi'] = { display_name: 'Rssi', value: view.readU8() };
d.alarms['cap']= { display_name: 'Capacity', value: view.readU16() };
d.alarms['time'] = { display_name: 'Minutes', value: view.readU16() };
if (semver.lt(CONFIG.apiVersion, "1.36.0")) {
d.alarms['time'] = { display_name: 'Minutes', value: view.readU16() };
} else {
// This value is unused in configurable timers
view.readU16();
}
d.alarms['alt'] = { display_name: 'Altitude', value: view.readU16() };
}
}
}
d.state = {};
d.state.haveSomeOsd = (d.flags != 0)
d.state.haveSomeOsd = (d.flags != 0)
d.state.haveMax7456Video = bit_check(d.flags, 4) || (d.flags == 1 && semver.lt(CONFIG.apiVersion, "1.34.0"));
d.state.haveOsdFeature = bit_check(d.flags, 0) || (d.flags == 1 && semver.lt(CONFIG.apiVersion, "1.34.0"));
d.state.isOsdSlave = bit_check(d.flags, 1) && semver.gte(CONFIG.apiVersion, "1.34.0");
d.display_items = [];
d.stat_items = [];
d.timers = [];
// Parse display element positions
while (view.offset < view.byteLength && d.display_items.length < OSD.constants.DISPLAY_FIELDS.length) {
@ -836,12 +933,16 @@ OSD.msp = {
desc: c.desc,
index: j,
positionable: c.positionable,
preview: typeof(c.preview) === 'function' ? c.preview(d) : c.preview
preview: c.preview
}, this.helpers.unpack.position(v, c)));
}
if (semver.gte(CONFIG.apiVersion, "1.36.0")) {
// Parse statistics display enable
var expectedStatsCount = view.readU8();
if (expectedStatsCount != OSD.constants.STATISTIC_FIELDS.length) {
console.error("Firmware is transmitting a different number of statistics (" + expectedStatsCount + ") to what the configurator is expecting (" + OSD.constants.STATISTIC_FIELDS.length + ")");
}
while (view.offset < view.byteLength && d.stat_items.length < OSD.constants.STATISTIC_FIELDS.length) {
var v = view.readU8();
var j = d.stat_items.length;
@ -852,6 +953,35 @@ OSD.msp = {
index: j,
enabled: v === 1
});
expectedStatsCount--;
}
// Read all the data for any statistics we don't know about
while (expectedStatsCount > 0) {
view.readU8();
expectedStatsCount--;
}
// Parse configurable timers
var expectedTimersCount = view.readU8();
while (view.offset < view.byteLength) {
var v = view.readU16();
var j = d.timers.length;
d.timers.push($.extend({
index: j,
}, this.helpers.unpack.timer(v, c)));
expectedTimersCount--;
}
// Read all the data for any timers we don't know about
while (expectedTimersCount > 0) {
view.readU16();
expectedTimersCount--;
}
}
// Generate OSD element previews that are defined by a function
for (let item of d.display_items) {
if (typeof(item.preview) === 'function') {
item.preview = item.preview(d);
}
}
@ -1014,8 +1144,65 @@ TABS.osd.initialize = function (callback) {
$alarms.append($input);
}
// Post flight status
if (semver.gte(CONFIG.apiVersion, "1.36.0")) {
// Timers
$('.timers-container').show();
var $timers = $('#timer-fields').empty();
for (let tim of OSD.data.timers) {
var $timerConfig = $('<div class="switchable-field field-' + tim.index + '"/>');
// Timer number
$timerConfig.append('<span>' + (tim.index + 1) + '</span>');
// Source
var src = $('<select class="timer-option osd_tip" id="' + tim.index + '"></select>');
src.attr('title', chrome.i18n.getMessage('osdTimerSourceTooltip'));
OSD.constants.TIMER_TYPES.forEach(function(e, i) {
src.append('<option value="' + i + '">' + e + '</option>');
});
src[0].selectedIndex = tim.src;
src.blur(function(e) {
OSD.data.timers[$(this)[0].id].src = $(this)[0].selectedIndex;
MSP.promise(MSPCodes.MSP_SET_OSD_CONFIG, OSD.msp.encodeTimer(OSD.data.timers[$(this)[0].id]))
.then(function() {
updateOsdView();
});
});
$timerConfig.append(src);
// Precision
var precision = $('<select class="timer-option osd_tip" id="' + tim.index + '"></select>');
precision.attr('title', chrome.i18n.getMessage('osdTimerPrecisionTooltip'));
OSD.constants.TIMER_PRECISION.forEach(function(e, i) {
precision.append('<option value="' + i + '">' + e + '</option>');
});
precision[0].selectedIndex = tim.precision;
precision.blur(function(e) {
OSD.data.timers[$(this)[0].id].precision = $(this)[0].selectedIndex;
MSP.promise(MSPCodes.MSP_SET_OSD_CONFIG, OSD.msp.encodeTimer(OSD.data.timers[$(this)[0].id]))
.then(function() {
updateOsdView();
});
});
$timerConfig.append(precision);
// Alarm
var alarm = $('<input class="timer-option osd_tip" name="alarm" type="number" min=0 id="' + tim.index + '"/>');
alarm.attr('title', chrome.i18n.getMessage('osdTimerAlarmTooltip'));
alarm[0].value = tim.alarm;
alarm.blur(function(e) {
OSD.data.timers[$(this)[0].id].alarm = $(this)[0].value;
MSP.promise(MSPCodes.MSP_SET_OSD_CONFIG, OSD.msp.encodeTimer(OSD.data.timers[$(this)[0].id]))
.then(function() {
updateOsdView();
});
});
$timerConfig.append(alarm);
$timers.append($timerConfig);
}
// Post flight statistics
$('.stats-container').show();
var $statsFields = $('#post-flight-stat-fields').empty();