Merge pull request #1612 from McGiverGim/vtx_load_save

Add save/load buttons for the VTX Table
10.7.0-preview
Michael Keller 2019-09-04 23:30:16 +12:00 committed by GitHub
commit 7f1934b946
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 286 additions and 53 deletions

View File

@ -4784,6 +4784,10 @@
"message": "<span class=\"message-negative\">Attention:</span> You need to configure and save FIRST the VTX Table at the bottom before you can make use of the $t(vtxSelectedMode.message) fields.", "message": "<span class=\"message-negative\">Attention:</span> You need to configure and save FIRST the VTX Table at the bottom before you can make use of the $t(vtxSelectedMode.message) fields.",
"description": "Message to show when the VTX is not supported in the VTX tab" "description": "Message to show when the VTX is not supported in the VTX tab"
}, },
"vtxMessageVerifyTable": {
"message": "<span class=\"message-negative\">Attention:</span> The values of the VTX Table have been loaded, but not yet stored on the flight controller. You must verify and modify the values to be sure that they are valid and legal in your country and then press the $t(vtxButtonSave.message) button to store them on the flight controller.",
"description": "Message to show when the VTX Table has been loaded from a external source"
},
"vtxFrequencyChannel": { "vtxFrequencyChannel": {
"message": "Enter frequency directly", "message": "Enter frequency directly",
"description": "Text of one of the fields of the VTX tab" "description": "Text of one of the fields of the VTX tab"
@ -4972,6 +4976,31 @@
"message": "This table represents all the frequencies that can be used for your VTX. You can have several bands and for each band you must configure:<br><b>- $t(vtxTableBandTitleName.message):</b> Name that you want to assign to this band, like BOSCAM_A, FATSHARK or RACEBAND.<br><b>- $t(vtxTableBandTitleLetter.message):</b> Short letter that references the band.<br><b>- $t(vtxTableBandTitleFactory.message):</b> This indicates if it is a factory band. If enabled Betaflight sends to the VTX a band and channel number. The VTX will then use its built-in frequency table and the frequencies configured here are only to show the value in the OSD and other places. If it is not enabled, then Betaflight will send to the VTX the real frequency configured here.<br><b>- Frequencies:</b> Frequencies for this band.<br><br>Remember that not all frequencies are legal at your country. You must put a value of <b>zero</b> to each frequency index that you are not allowed to use to disable it.", "message": "This table represents all the frequencies that can be used for your VTX. You can have several bands and for each band you must configure:<br><b>- $t(vtxTableBandTitleName.message):</b> Name that you want to assign to this band, like BOSCAM_A, FATSHARK or RACEBAND.<br><b>- $t(vtxTableBandTitleLetter.message):</b> Short letter that references the band.<br><b>- $t(vtxTableBandTitleFactory.message):</b> This indicates if it is a factory band. If enabled Betaflight sends to the VTX a band and channel number. The VTX will then use its built-in frequency table and the frequencies configured here are only to show the value in the OSD and other places. If it is not enabled, then Betaflight will send to the VTX the real frequency configured here.<br><b>- Frequencies:</b> Frequencies for this band.<br><br>Remember that not all frequencies are legal at your country. You must put a value of <b>zero</b> to each frequency index that you are not allowed to use to disable it.",
"description": "Help for the table of bands-channels that appears in the VTX tab" "description": "Help for the table of bands-channels that appears in the VTX tab"
}, },
"vtxSavedFileOk": {
"message": "VTX Config file <span class=\"message-positive\">saved</span>",
"description": "Message in the GUI log when the VTX Config file is saved"
},
"vtxSavedFileKo": {
"message": "<span class=\"message-negative\">Error</span> while saving the VTX Config file",
"description": "Message in the GUI log when the VTX Config file is saved"
},
"vtxLoadFileOk": {
"message": "VTX Config file <span class=\"message-positive\">loaded</span>",
"description": "Message in the GUI log when the VTX Config file is loaded"
},
"vtxLoadFileKo": {
"message": "<span class=\"message-negative\">Error</span> while loading the VTX Config file",
"description": "Message in the GUI log when the VTX Config file is loaded"
},
"vtxButtonSaveFile": {
"message": "Save to file",
"description": "Save to file button in the VTX tab"
},
"vtxButtonLoadFile": {
"message": "Load from file",
"description": "Load to file button in the VTX tab"
},
"vtxButtonSave": { "vtxButtonSave": {
"message": "Save", "message": "Save",
"description": "Save button in the VTX tab" "description": "Save button in the VTX tab"

View File

@ -2102,8 +2102,12 @@ MspHelper.prototype.crunch = function(code) {
buffer.push8(VTXTABLE_BAND.vtxtable_band_name.charCodeAt(i)); buffer.push8(VTXTABLE_BAND.vtxtable_band_name.charCodeAt(i));
} }
buffer.push8(VTXTABLE_BAND.vtxtable_band_letter.charCodeAt(0)) if (VTXTABLE_BAND.vtxtable_band_letter != '') {
.push8(VTXTABLE_BAND.vtxtable_band_is_factory_band ? 1 : 0); buffer.push8(VTXTABLE_BAND.vtxtable_band_letter.charCodeAt(0))
} else {
buffer.push8(' '.charCodeAt(0));
}
buffer.push8(VTXTABLE_BAND.vtxtable_band_is_factory_band ? 1 : 0);
buffer.push8(VTXTABLE_BAND.vtxtable_band_frequencies.length); buffer.push8(VTXTABLE_BAND.vtxtable_band_frequencies.length);
for (let i = 0; i < VTXTABLE_BAND.vtxtable_band_frequencies.length; i++) { for (let i = 0; i < VTXTABLE_BAND.vtxtable_band_frequencies.length; i++) {

View File

@ -2,6 +2,7 @@
TABS.vtx = { TABS.vtx = {
supported: false, supported: false,
vtxTableSavePending: false,
MAX_POWERLEVEL_VALUES: 8, MAX_POWERLEVEL_VALUES: 8,
MAX_BAND_VALUES: 8, MAX_BAND_VALUES: 8,
MAX_BAND_CHANNELS_VALUES: 8, MAX_BAND_CHANNELS_VALUES: 8,
@ -91,6 +92,42 @@ TABS.vtx.initialize = function (callback) {
} }
} }
// Emulates the MSP read from a vtxConfig object (JSON)
function read_vtx_config_json(vtxConfig, vtxcallback_after_read) {
// Bands and channels
VTX_CONFIG.vtx_table_bands = vtxConfig.vtx_table.bands_list.length;
let maxChannels = 0;
TABS.vtx.VTXTABLE_BAND_LIST = [];
for (let i = 1; i <= VTX_CONFIG.vtx_table_bands; i++) {
TABS.vtx.VTXTABLE_BAND_LIST[i - 1] = {};
TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_number = i;
TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_name = vtxConfig.vtx_table.bands_list[i - 1].name;
TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_letter = vtxConfig.vtx_table.bands_list[i - 1].letter;
TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_is_factory_band = vtxConfig.vtx_table.bands_list[i - 1].is_factory_band;
TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_frequencies = vtxConfig.vtx_table.bands_list[i - 1].frequencies;
maxChannels = Math.max(maxChannels, TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_frequencies.length);
}
VTX_CONFIG.vtx_table_channels = maxChannels;
// Power levels
VTX_CONFIG.vtx_table_powerlevels = vtxConfig.vtx_table.powerlevels_list.length;
TABS.vtx.VTXTABLE_POWERLEVEL_LIST = [];
for (let i = 1; i <= VTX_CONFIG.vtx_table_powerlevels; i++) {
TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1] = {};
TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_number = i;
TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_value = vtxConfig.vtx_table.powerlevels_list[i - 1].value;
TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_label = vtxConfig.vtx_table.powerlevels_list[i - 1].label;
}
vtxcallback_after_read();
}
// Prepares all the UI elements, the MSP command has been executed before // Prepares all the UI elements, the MSP command has been executed before
function initDisplay() { function initDisplay() {
@ -121,6 +158,7 @@ TABS.vtx.initialize = function (callback) {
$(".vtx_not_supported").toggle(!vtxSupported); $(".vtx_not_supported").toggle(!vtxSupported);
$(".vtx_table_available").toggle(vtxSupported && VTX_CONFIG.vtx_table_available); $(".vtx_table_available").toggle(vtxSupported && VTX_CONFIG.vtx_table_available);
$(".vtx_table_not_configured").toggle(vtxTableNotConfigured); $(".vtx_table_not_configured").toggle(vtxTableNotConfigured);
$(".vtx_table_save_pending").toggle(TABS.vtx.vtxTableSavePending);
// Insert actual values in the fields // Insert actual values in the fields
// Values of the selected mode // Values of the selected mode
@ -429,64 +467,130 @@ TABS.vtx.initialize = function (callback) {
return powerMinMax; return powerMinMax;
} }
// Save function // Save and other button functions
$('a.save_file').click(function () {
save_json();
});
$('a.load_file').click(function () {
load_json();
});
$('a.save').click(function () { $('a.save').click(function () {
save_vtx(); save_vtx();
}); });
} }
function save_json() {
let suggestedName = 'vtxtable';
let suffix = 'json';
var filename = generateFilename(suggestedName, suffix);
let accepts = [{
description: suffix.toUpperCase() + ' files', extensions: [suffix],
}];
chrome.fileSystem.chooseEntry({type: 'saveFile', suggestedName: filename, accepts: accepts}, function(entry) {
if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError.message);
return;
}
if (!entry) {
console.log('No file selected');
return;
}
entry.createWriter(function (writer) {
writer.onerror = function(){
console.error('Failed to write VTX file');
GUI.log(i18n.getMessage('vtxSavedFileKo'));
};
writer.onwriteend = function() {
// we get here at the end of the truncate method, change to the new end
writer.onwriteend = function() {
console.log('Write VTX file end');
GUI.log(i18n.getMessage('vtxSavedFileOk'));
}
dump_html_to_msp();
let vtxConfig = createVtxConfigInfo();
let text = JSON.stringify(vtxConfig, null, 4);
let data = new Blob([text], { type: "application/json" });
writer.write(data);
};
writer.truncate(0);
}, function (){
console.error('Failed to get VTX file writer');
GUI.log(i18n.getMessage('vtxSavedFileKo'));
});
});
}
function load_json() {
let suffix = 'json';
let accepts = [{
description: suffix.toUpperCase() + ' files', extensions: [suffix],
}];
chrome.fileSystem.chooseEntry({type: 'openFile', accepts: accepts}, function(entry) {
if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError.message);
return;
}
if (!entry) {
console.log('No file selected');
return;
}
entry.file(function(file) {
let reader = new FileReader();
reader.onload = function(e) {
let text = e.target.result;
try {
let vtxConfig = JSON.parse(text);
read_vtx_config_json(vtxConfig, load_html);
TABS.vtx.vtxTableSavePending = true;
console.log('Load VTX file end');
GUI.log(i18n.getMessage('vtxLoadFileOk'));
} catch (err) {
console.error('Failed loading VTX file config');
GUI.log(i18n.getMessage('vtxLoadFileKo'));
}
};
reader.readAsText(file);
}, function() {
console.error('Failed to get VTX file reader');
GUI.log(i18n.getMessage('vtxLoadFileKo'));
});
});
}
// Save all the values from the tab to MSP // Save all the values from the tab to MSP
function save_vtx() { function save_vtx() {
// General config dump_html_to_msp();
let frequencyEnabled = $("#vtx_frequency_channel").prop('checked');
if (frequencyEnabled) {
VTX_CONFIG.vtx_frequency = parseInt($("#vtx_frequency").val());
VTX_CONFIG.vtx_band = 0;
VTX_CONFIG.vtx_channel = 0;
} else {
VTX_CONFIG.vtx_band = parseInt($("#vtx_band").val());
VTX_CONFIG.vtx_channel = parseInt($("#vtx_channel").val());
VTX_CONFIG.vtx_frequency = 0;
if (semver.lt(CONFIG.apiVersion, "1.42.0")) {
if (VTX_CONFIG.vtx_band > 0 || VTX_CONFIG.vtx_channel > 0) {
VTX_CONFIG.vtx_frequency = (band - 1) * 8 + (channel - 1);
}
}
}
VTX_CONFIG.vtx_power = parseInt($("#vtx_power").val());
VTX_CONFIG.vtx_pit_mode = $("#vtx_pit_mode").prop('checked');
VTX_CONFIG.vtx_low_power_disarm = parseInt($("#vtx_low_power_disarm").val());
VTX_CONFIG.vtx_table_clear = true;
// Power levels
VTX_CONFIG.vtx_table_powerlevels = parseInt($("#vtx_table_powerlevels").val());
TABS.vtx.VTXTABLE_POWERLEVEL_LIST = [];
for (let i = 1; i <= VTX_CONFIG.vtx_table_powerlevels; i++) {
TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1] = {};
TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_number = i;
TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_value = parseInt($("#vtx_table_powerlevels_" + i).val());
TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_label = $("#vtx_table_powerlabels_" + i).val();
}
// Bands and channels
VTX_CONFIG.vtx_table_bands = parseInt($("#vtx_table_bands").val());
VTX_CONFIG.vtx_table_channels = parseInt($("#vtx_table_channels").val());
TABS.vtx.VTXTABLE_BAND_LIST = [];
for (let i = 1; i <= VTX_CONFIG.vtx_table_bands; i++) {
TABS.vtx.VTXTABLE_BAND_LIST[i - 1] = {};
TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_number = i;
TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_name = $("#vtx_table_band_name_" + i).val();
TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_letter = $("#vtx_table_band_letter_" + i).val();
TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_is_factory_band = $("#vtx_table_band_factory_" + i).prop('checked');
TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_frequencies = [];
for (let j = 1; j <= VTX_CONFIG.vtx_table_channels; j++) {
TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_frequencies.push(parseInt($("#vtx_table_band_channel_" + i + "_" + j).val()));
}
}
// Start MSP saving // Start MSP saving
save_vtx_config(); save_vtx_config();
@ -540,6 +644,8 @@ TABS.vtx.initialize = function (callback) {
function save_completed() { function save_completed() {
GUI.log(i18n.getMessage('configurationEepromSaved')); GUI.log(i18n.getMessage('configurationEepromSaved'));
TABS.vtx.vtxTableSavePending = false;
var oldText = $("#save_button").text(); var oldText = $("#save_button").text();
$("#save_button").html(i18n.getMessage('vtxButtonSaved')); $("#save_button").html(i18n.getMessage('vtxButtonSaved'));
setTimeout(function () { setTimeout(function () {
@ -549,11 +655,95 @@ TABS.vtx.initialize = function (callback) {
TABS.vtx.initialize(); TABS.vtx.initialize();
} }
} }
function dump_html_to_msp() {
// General config
let frequencyEnabled = $("#vtx_frequency_channel").prop('checked');
if (frequencyEnabled) {
VTX_CONFIG.vtx_frequency = parseInt($("#vtx_frequency").val());
VTX_CONFIG.vtx_band = 0;
VTX_CONFIG.vtx_channel = 0;
} else {
VTX_CONFIG.vtx_band = parseInt($("#vtx_band").val());
VTX_CONFIG.vtx_channel = parseInt($("#vtx_channel").val());
VTX_CONFIG.vtx_frequency = 0;
if (semver.lt(CONFIG.apiVersion, "1.42.0")) {
if (VTX_CONFIG.vtx_band > 0 || VTX_CONFIG.vtx_channel > 0) {
VTX_CONFIG.vtx_frequency = (band - 1) * 8 + (channel - 1);
}
}
}
VTX_CONFIG.vtx_power = parseInt($("#vtx_power").val());
VTX_CONFIG.vtx_pit_mode = $("#vtx_pit_mode").prop('checked');
VTX_CONFIG.vtx_low_power_disarm = parseInt($("#vtx_low_power_disarm").val());
VTX_CONFIG.vtx_table_clear = true;
// Power levels
VTX_CONFIG.vtx_table_powerlevels = parseInt($("#vtx_table_powerlevels").val());
TABS.vtx.VTXTABLE_POWERLEVEL_LIST = [];
for (let i = 1; i <= VTX_CONFIG.vtx_table_powerlevels; i++) {
TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1] = {};
TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_number = i;
TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_value = parseInt($("#vtx_table_powerlevels_" + i).val());
TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_label = $("#vtx_table_powerlabels_" + i).val();
}
// Bands and channels
VTX_CONFIG.vtx_table_bands = parseInt($("#vtx_table_bands").val());
VTX_CONFIG.vtx_table_channels = parseInt($("#vtx_table_channels").val());
TABS.vtx.VTXTABLE_BAND_LIST = [];
for (let i = 1; i <= VTX_CONFIG.vtx_table_bands; i++) {
TABS.vtx.VTXTABLE_BAND_LIST[i - 1] = {};
TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_number = i;
TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_name = $("#vtx_table_band_name_" + i).val();
TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_letter = $("#vtx_table_band_letter_" + i).val();
TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_is_factory_band = $("#vtx_table_band_factory_" + i).prop('checked');
TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_frequencies = [];
for (let j = 1; j <= VTX_CONFIG.vtx_table_channels; j++) {
TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_frequencies.push(parseInt($("#vtx_table_band_channel_" + i + "_" + j).val()));
}
}
}
// Copies from the MSP data to the vtxInfo object (JSON)
function createVtxConfigInfo() {
let vtxConfig = {};
vtxConfig.description = "Betaflight VTX Config file";
vtxConfig.version = "1.0";
vtxConfig.vtx_table = {};
vtxConfig.vtx_table.bands_list = [];
for (let i = 1; i <= VTX_CONFIG.vtx_table_bands; i++) {
vtxConfig.vtx_table.bands_list[i - 1] = {};
vtxConfig.vtx_table.bands_list[i - 1].name = TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_name;
vtxConfig.vtx_table.bands_list[i - 1].letter = TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_letter;
vtxConfig.vtx_table.bands_list[i - 1].is_factory_band = TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_is_factory_band;
vtxConfig.vtx_table.bands_list[i - 1].frequencies = TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_frequencies;
}
vtxConfig.vtx_table.powerlevels_list = [];
for (let i = 1; i <= VTX_CONFIG.vtx_table_powerlevels; i++) {
vtxConfig.vtx_table.powerlevels_list[i - 1] = {};
vtxConfig.vtx_table.powerlevels_list[i - 1].value = TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_value;
vtxConfig.vtx_table.powerlevels_list[i - 1].label = TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_label;
}
return vtxConfig;
}
}; };
TABS.vtx.cleanup = function (callback) { TABS.vtx.cleanup = function (callback) {
// Add here things that need to be cleaned or closed before leaving the tab // Add here things that need to be cleaned or closed before leaving the tab
this.vtxTableSavePending = false;
this.VTXTABLE_BAND_LIST = []; this.VTXTABLE_BAND_LIST = [];
this.VTXTABLE_POWERLEVEL_LIST = []; this.VTXTABLE_POWERLEVEL_LIST = [];

View File

@ -190,6 +190,10 @@
<td> <td>
<div class="leftWrapper"> <div class="leftWrapper">
<div class="note note_spacer vtx_table_save_pending">
<div i18n="vtxMessageVerifyTable"/>
</div>
<div class="gui_box grey vtx_table_box vtx_table_available"> <div class="gui_box grey vtx_table_box vtx_table_available">
<div class="gui_box_titlebar"> <div class="gui_box_titlebar">
@ -269,6 +273,12 @@
</div> </div>
<div class="content_toolbar"> <div class="content_toolbar">
<div class="btn save_file_btn">
<a class="save_file" id="save_file_button" href="#" i18n="vtxButtonSaveFile"></a>
</div>
<div class="btn load_file_btn">
<a class="load_file" id="load_file_button" href="#" i18n="vtxButtonLoadFile"></a>
</div>
<div class="btn save_btn"> <div class="btn save_btn">
<a class="save" id="save_button" href="#" i18n="vtxButtonSave"></a> <a class="save" id="save_button" href="#" i18n="vtxButtonSave"></a>
</div> </div>
@ -282,7 +292,7 @@
<div id="tab-vtx-powerlevel-values"> <div id="tab-vtx-powerlevel-values">
<table> <table>
<tr> <tr>
<td><span class="numberspacer field_powerlevel_value"><input type="number" id="vtx_table_powerlevels" min="0" max="65535"></span></td> <td><span class="numberspacer field_powerlevel_value"><input type="number" id="vtx_table_powerlevels" min="0" max="65535" value="0"></span></td>
</tr> </tr>
</table> </table>
</div> </div>
@ -319,7 +329,7 @@
<div id="tab-vtx-channels"> <div id="tab-vtx-channels">
<table> <table>
<tr> <tr>
<td><span class="numberspacer field_band_channel "><input class="frequency_input" type="number" id="vtx_table_band_channel" min="0" max="5999"></span></td> <td><span class="numberspacer field_band_channel "><input class="frequency_input" type="number" id="vtx_table_band_channel" min="0" max="5999" value="0"></span></td>
</tr> </tr>
</table> </table>
</div> </div>