1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-16 21:05:35 +03:00

whitespace trimming run

This commit is contained in:
cTn 2014-03-08 06:25:15 +01:00
parent 0607ccbff4
commit 9b29f78e3e
44 changed files with 1208 additions and 1208 deletions

View file

@ -1,11 +1,11 @@
/*
resizable: false - Keep in mind this only disables the side/corner resizing via mouse, nothing more
maxWidth / maxHeight - is defined to prevent application reaching maximized state through window manager
We are setting Bounds through setBounds method after window was created because on linux setting Bounds as
window.create property seemed to fail, probably because "previous" bounds was used instead according to docs.
bounds - Size and position of the content in the window (excluding the titlebar).
bounds - Size and position of the content in the window (excluding the titlebar).
If an id is also specified and a window with a matching id has been shown before, the remembered bounds of the window will be used instead.
*/
function start_app() {
@ -16,19 +16,19 @@ function start_app() {
}, function(createdWindow) {
// set window size
createdWindow.setBounds({'width': 962, 'height': 650});
// bind events
createdWindow.onMaximized.addListener(function() {
createdWindow.restore();
});
createdWindow.onClosed.addListener(function() {
// connectionId is passed from the script side through the chrome.runtime.getBackgroundPage refference
// allowing us to automatically close the port when application shut down
// save connectionId in separate variable before app_window is destroyed
var connectionId = app_window.serial.connectionId;
if (connectionId > 0) {
chrome.serial.disconnect(connectionId, function(result) {
console.log('SERIAL: Connection closed - ' + result);
@ -43,8 +43,8 @@ chrome.app.runtime.onLaunched.addListener(function() {
});
chrome.runtime.onInstalled.addListener(function(details) {
if (details.reason == 'update') {
var manifest = chrome.runtime.getManifest();
if (details.reason == 'update') {
var manifest = chrome.runtime.getManifest();
var options = {
priority: 0,
type: 'basic',
@ -53,7 +53,7 @@ chrome.runtime.onInstalled.addListener(function(details) {
iconUrl: '/images/icon_128.png',
buttons: [{'title': 'Click this button to start the application'}]
};
chrome.notifications.create('baseflight_update', options, function(notificationId) {
// empty
});

View file

@ -21,15 +21,15 @@ a:hover {
}
input[type="number"]::-webkit-inner-spin-button {
-webkit-appearance: none;
display: block;
opacity: 1; /* required for chromium 33+ beta */
width: 15px;
background-image: url('../images/arrows.png');
background-repeat: no-repeat;
border-left: 1px solid silver;
}
.clear-both {
@ -47,44 +47,44 @@ input[type="number"]::-webkit-inner-spin-button {
#frame {
height: 25px;
line-height: 25px;
-webkit-app-region: drag;
background-color: white;
}
#frame .title {
float: left;
margin-left: 15px;
font-weight: bold;
/* text-shadow: 1px 1px #e4e4e4; */
}
#frame .minimize {
float: right;
display: block;
width: 26px;
height: 20px;
background: url('../images/controls/minimize.png') no-repeat 0 0;
}
#frame .maximize {
float: right;
display: block;
width: 27px;
height: 20px;
background: url('../images/controls/maximize.png') no-repeat 0 0;
}
}
#frame .close {
float: right;
display: block;
width: 45px;
height: 20px;
background: url('../images/controls/close.png') no-repeat 0 0;
}
#frame a {
@ -93,7 +93,7 @@ input[type="number"]::-webkit-inner-spin-button {
}
#frame a:hover {
/* hover is disabled untill webkit-app-region: drag; starts to fire events or chromium implements native frame */
/* background-position: 0px -20px; */
/* background-position: 0px -20px; */
}
#frame a:active {
background-position: 0px -40px;
@ -101,12 +101,12 @@ input[type="number"]::-webkit-inner-spin-button {
#main-wrapper {
width: 940px;
margin: 10px auto 0 auto;
padding: 0 10px 0 10px;
}
#port-picker {
float: left;
height: 22px;
margin-bottom: 10px;
}
@ -116,10 +116,10 @@ input[type="number"]::-webkit-inner-spin-button {
#port-picker select {
height: 20px;
line-height: 20px;
float: left;
margin-right: 10px;
border: 1px solid silver;
}
#port-picker #port {
@ -133,19 +133,19 @@ input[type="number"]::-webkit-inner-spin-button {
}
#port-picker a {
float: left;
display: block;
width: 80px;
height: 18px;
border: 1px solid silver;
line-height: 18px;
text-align: center;
}
#port-picker a.connect {
margin-right: 10px;
background-color: #be2222;
color: white;
}
@ -161,32 +161,32 @@ input[type="number"]::-webkit-inner-spin-button {
}
#port-picker input.auto_connect {
float: left;
margin-top: 4px;
}
#port-picker span.auto_connect {
float: left;
margin: 3px 0 0 5px;
}
#sensor-status {
float: right;
height: 22px;
line-height: 22px;
}
#sensor-status li {
float: left;
margin-left: 10px;
padding: 0 12px 0 12px;
height: 18px;
line-height: 18px;
color: white;
text-align: center;
border: 1px solid #c0c0c0;
border-radius: 8px;
background-color: #be2222;
@ -194,45 +194,45 @@ input[type="number"]::-webkit-inner-spin-button {
#sensor-status .on {
background-color: #0d8b13;
}
#log {
#log {
margin-bottom: 10px;
height: 60px;
border: 1px solid silver;
background-color: white;
overflow-y: scroll;
}
}
#log .wrapper {
padding: 5px;
-webkit-user-select: text;
}
}
#tabs {
position: absolute;
margin-top: 1px;
z-index: 10;
font-weight: bold;
}
#tabs li {
float: left;
margin-right: 5px;
border: 1px solid #848484;
border-bottom: 0;
}
#tabs li a {
display: block;
height: 15px;
padding: 5px;
padding-left: 12px;
padding-right: 12px;
background-color: #d0d0d0;
}
#tabs li a:hover {
@ -243,38 +243,38 @@ input[type="number"]::-webkit-inner-spin-button {
}
#tabs li.active a {
height: 16px;
background-color: white;
background-color: white;
}
#tabs li.active a:hover {
#tabs li.active a:hover {
cursor: default;
background-color: white;
}
background-color: white;
}
#content {
margin-top: 37px;
padding: 10px;
background-color: white;
height: 429px;
overflow-x: hidden;
overflow-y: auto;
border: 1px solid #848484;
-webkit-transform: rotateX(0deg); /* DO NOT REMOVE! this fixes the UI freezing bug on MAC OS X */
}
}
#status-bar {
margin-left: -10px;
margin-top: 10px;
width: 940px;
height: 20px;
line-height: 20px;
padding: 0 10px 0 10px;
border-top: 1px solid #7d7d79;
background-color: #bfbeb5;
}

View file

@ -17,27 +17,27 @@ function configuration_backup() {
});
});
});
var backup = function() {
var chosenFileEntry = null;
var accepts = [{
extensions: ['txt']
}];
// generate timestamp for the backup file
var d = new Date();
var now = d.getUTCFullYear() + '.' + d.getDate() + '.' + (d.getMonth() + 1) + '.' + d.getHours() + '.' + d.getMinutes();
var now = d.getUTCFullYear() + '.' + d.getDate() + '.' + (d.getMonth() + 1) + '.' + d.getHours() + '.' + d.getMinutes();
// create or load the file
chrome.fileSystem.chooseEntry({type: 'saveFile', suggestedName: 'bf_mw_backup_' + now, accepts: accepts}, function(fileEntry) {
if (!fileEntry) {
console.log('No file selected, backup aborted.');
return;
}
chosenFileEntry = fileEntry;
chosenFileEntry = fileEntry;
// echo/console log path specified
chrome.fileSystem.getDisplayPath(chosenFileEntry, function(path) {
@ -50,7 +50,7 @@ function configuration_backup() {
chrome.fileSystem.isWritableEntry(fileEntryWritable, function(isWritable) {
if (isWritable) {
chosenFileEntry = fileEntryWritable;
// create config object that will be used to store all downloaded data
var configuration = {
'firmware_version': CONFIG.version,
@ -61,29 +61,29 @@ function configuration_backup() {
'AccelTrim': CONFIG.accelerometerTrims,
'MISC': MISC
};
// crunch the config object
var serialized_config_object = JSON.stringify(configuration);
var blob = new Blob([serialized_config_object], {type: 'text/plain'}); // first parameter for Blob needs to be an array
chosenFileEntry.createWriter(function(writer) {
writer.onerror = function (e) {
console.error(e);
};
var truncated = false;
writer.onwriteend = function() {
if (!truncated) {
// onwriteend will be fired again when truncation is finished
truncated = true;
writer.truncate(blob.size);
return;
}
console.log('Write SUCCESSFUL');
};
writer.write(blob);
}, function (e) {
console.error(e);
@ -100,25 +100,25 @@ function configuration_backup() {
function configuration_restore() {
var chosenFileEntry = null;
var accepts = [{
extensions: ['txt']
}];
// load up the file
chrome.fileSystem.chooseEntry({type: 'openFile', accepts: accepts}, function(fileEntry) {
if (!fileEntry) {
console.log('No file selected, restore aborted.');
return;
}
chosenFileEntry = fileEntry;
chosenFileEntry = fileEntry;
// echo/console log path specified
chrome.fileSystem.getDisplayPath(chosenFileEntry, function(path) {
console.log('Restore file path: ' + path);
});
});
// read contents into variable
chosenFileEntry.file(function(file) {
@ -131,31 +131,31 @@ function configuration_restore() {
reader.abort();
}
};
reader.onloadend = function(e) {
if (e.total != 0 && e.total == e.loaded) {
console.log('Read SUCCESSFUL');
try { // check if string provided is a valid JSON
var deserialized_configuration_object = JSON.parse(e.target.result);
} catch (e) {
// data provided != valid json object
console.log('Data provided != valid JSON string, restore aborted.');
return;
}
// replacing "old configuration" with configuration from backup file
var configuration = deserialized_configuration_object;
// some configuration.VERSION code goes here? will see
PIDs = configuration.PID;
AUX_CONFIG_values = configuration.AUX_val;
RC_tuning = configuration.RC;
CONFIG.accelerometerTrims = configuration.AccelTrim;
MISC = configuration.MISC;
// all of the arrays/objects are set, upload changes
configuration_upload();
}
@ -177,11 +177,11 @@ function configuration_upload() {
var PID_buffer_needle = 0;
for (var i = 0; i < PIDs.length; i++) {
switch (i) {
case 0:
case 1:
case 2:
case 3:
case 7:
case 0:
case 1:
case 2:
case 3:
case 7:
case 8:
case 9:
PID_buffer_out[PID_buffer_needle] = parseInt(PIDs[i][0] * 10);
@ -193,20 +193,20 @@ function configuration_upload() {
PID_buffer_out[PID_buffer_needle + 1] = parseInt(PIDs[i][1] * 100);
PID_buffer_out[PID_buffer_needle + 2] = parseInt(PIDs[i][2]);
break;
case 5:
case 5:
case 6:
PID_buffer_out[PID_buffer_needle] = parseInt(PIDs[i][0] * 10);
PID_buffer_out[PID_buffer_needle + 1] = parseInt(PIDs[i][1] * 100);
PID_buffer_out[PID_buffer_needle + 2] = parseInt(PIDs[i][2] * 1000);
break;
break;
}
PID_buffer_needle += 3;
}
// Send over the PID changes
send_message(MSP_codes.MSP_SET_PID, PID_buffer_out, false, function() {
rc_tuning();
});
});
var rc_tuning = function() {
// RC Tuning section
@ -218,23 +218,23 @@ function configuration_upload() {
RC_tuning_buffer_out[4] = parseInt(RC_tuning.dynamic_THR_PID * 100);
RC_tuning_buffer_out[5] = parseInt(RC_tuning.throttle_MID * 100);
RC_tuning_buffer_out[6] = parseInt(RC_tuning.throttle_EXPO * 100);
// Send over the RC_tuning changes
send_message(MSP_codes.MSP_SET_RC_TUNING, RC_tuning_buffer_out, false, function() {
aux();
});
};
var aux = function() {
// AUX section
var AUX_val_buffer_out = new Array();
var needle = 0;
for (var i = 0; i < AUX_CONFIG_values.length; i++) {
AUX_val_buffer_out[needle++] = lowByte(AUX_CONFIG_values[i]);
AUX_val_buffer_out[needle++] = highByte(AUX_CONFIG_values[i]);
}
// Send over the AUX changes
send_message(MSP_codes.MSP_SET_BOX, AUX_val_buffer_out, false, function() {
trim();
@ -248,7 +248,7 @@ function configuration_upload() {
buffer_out[0] = lowByte(CONFIG.accelerometerTrims[0]);
buffer_out[1] = highByte(CONFIG.accelerometerTrims[0]);
buffer_out[2] = lowByte(CONFIG.accelerometerTrims[1]);
buffer_out[3] = highByte(CONFIG.accelerometerTrims[1]);
buffer_out[3] = highByte(CONFIG.accelerometerTrims[1]);
// Send over the new trims
send_message(MSP_codes.MSP_SET_ACC_TRIM, buffer_out, false, function() {
@ -282,7 +282,7 @@ function configuration_upload() {
buffer_out[19] = MISC.vbatmincellvoltage;
buffer_out[20] = MISC.vbatmaxcellvoltage;
buffer_out[21] = 0; // vbatlevel_crit (unused)
// Send ove the new MISC
send_message(MSP_codes.MSP_SET_MISC, buffer_out, false, function() {
// Save changes to EEPROM
@ -290,5 +290,5 @@ function configuration_upload() {
GUI.log('EEPROM <span style="color: green">saved</span>');
});
});
};
};
}

View file

@ -10,7 +10,7 @@ var CONFIG = {
activeSensors: 0,
mode: 0,
profile: 0,
uid: [0, 0, 0],
accelerometerTrims: [0, 0]
};
@ -71,7 +71,7 @@ var GPS_DATA = {
distanceToHome: 0,
ditectionToHome: 0,
update: 0,
// baseflight specific gps stuff
chn: new Array(),
svid: new Array(),

104
js/gui.js
View file

@ -6,7 +6,7 @@ var GUI_control = function() {
this.operating_system;
this.interval_array = [];
this.timeout_array = [];
// check which operating system is user running
if (navigator.appVersion.indexOf("Win") != -1) this.operating_system = "Windows";
else if (navigator.appVersion.indexOf("Mac") != -1) this.operating_system = "MacOS";
@ -23,19 +23,19 @@ var GUI_control = function() {
// first = true/false if code should be ran initially before next timer interval hits
GUI_control.prototype.interval_add = function(name, code, interval, first) {
var data = {'name': name, 'timer': undefined, 'code': code, 'interval': interval, 'fired': 0, 'paused': false};
if (first == true) {
code(); // execute code
data.fired++; // increment counter
}
data.timer = setInterval(function() {
code(); // execute code
data.fired++; // increment counter
}, interval);
this.interval_array.push(data); // push to primary interval array
};
@ -44,13 +44,13 @@ GUI_control.prototype.interval_remove = function(name) {
for (var i = 0; i < this.interval_array.length; i++) {
if (this.interval_array[i].name == name) {
clearInterval(this.interval_array[i].timer); // stop timer
this.interval_array.splice(i, 1); // remove element/object from array
return true;
}
}
return false;
};
@ -60,11 +60,11 @@ GUI_control.prototype.interval_pause = function(name) {
if (this.interval_array[i].name == name) {
clearInterval(this.interval_array[i].timer);
this.interval_array[i].paused = true;
return true;
}
}
return false;
};
@ -73,19 +73,19 @@ GUI_control.prototype.interval_resume = function(name) {
for (var i = 0; i < this.interval_array.length; i++) {
if (this.interval_array[i].name == name && this.interval_array[i].paused) {
var obj = this.interval_array[i];
obj.timer = setInterval(function() {
obj.code(); // execute code
obj.fired++; // increment counter
}, obj.interval);
obj.paused = false;
return true;
}
}
return false;
};
@ -94,7 +94,7 @@ GUI_control.prototype.interval_resume = function(name) {
GUI_control.prototype.interval_kill_all = function(keep_array) {
var self = this;
var timers_killed = 0;
for (var i = (this.interval_array.length - 1); i >= 0; i--) { // reverse iteration
var keep = false;
if (keep_array) { // only run through the array if it exists
@ -104,17 +104,17 @@ GUI_control.prototype.interval_kill_all = function(keep_array) {
}
});
}
if (!keep) {
clearInterval(this.interval_array[i].timer); // stop timer
this.interval_array[i].timer = undefined; // set timer property to undefined (mostly for debug purposes, but it doesn't hurt to have it here)
this.interval_array.splice(i, 1); // remove element/object from array
timers_killed++;
}
}
return timers_killed;
};
@ -126,10 +126,10 @@ GUI_control.prototype.timeout_add = function(name, code, timeout) {
// start timer with "cleaning" callback
var timer = setTimeout(function() {
code(); // execute code
self.timeout_remove(name); // cleanup
}, timeout);
this.timeout_array.push({'name': name, 'timer': timer, 'timeout': timeout}); // push to primary timeout array
};
@ -138,13 +138,13 @@ GUI_control.prototype.timeout_remove = function(name) {
for (var i = 0; i < this.timeout_array.length; i++) {
if (this.timeout_array[i].name == name) {
clearTimeout(this.timeout_array[i].timer); // stop timer
this.timeout_array.splice(i, 1); // remove element/object from array
return true;
}
}
return false;
};
@ -152,15 +152,15 @@ GUI_control.prototype.timeout_remove = function(name) {
// return = returns timers killed in last call
GUI_control.prototype.timeout_kill_all = function() {
var timers_killed = 0;
for (var i = 0; i < this.timeout_array.length; i++) {
clearTimeout(this.timeout_array[i].timer); // stop timer
timers_killed++;
}
this.timeout_array = []; // drop objects
return timers_killed;
};
@ -168,12 +168,12 @@ GUI_control.prototype.timeout_kill_all = function() {
GUI_control.prototype.log = function(message) {
var command_log = $('div#log');
var d = new Date();
var time = ((d.getHours() < 10) ? '0' + d.getHours(): d.getHours())
+ ':' + ((d.getMinutes() < 10) ? '0' + d.getMinutes(): d.getMinutes())
var time = ((d.getHours() < 10) ? '0' + d.getHours(): d.getHours())
+ ':' + ((d.getMinutes() < 10) ? '0' + d.getMinutes(): d.getMinutes())
+ ':' + ((d.getSeconds() < 10) ? '0' + d.getSeconds(): d.getSeconds());
$('div.wrapper', command_log).append('<p>' + time + ' -- ' + message + '</p>');
command_log.scrollTop($('div.wrapper', command_log).height());
command_log.scrollTop($('div.wrapper', command_log).height());
};
// Method is called every time a valid tab change event is received
@ -181,56 +181,56 @@ GUI_control.prototype.log = function(message) {
// default switch doesn't require callback to be set
GUI_control.prototype.tab_switch_cleanup = function(callback) {
MSP.callbacks_cleanup(); // we don't care about any old data that might or might not arrive
switch (this.active_tab) {
case 'initial_setup':
GUI.interval_remove('initial_setup_data_pull');
if (callback) callback();
break;
case 'pid_tuning':
GUI.interval_remove('pid_data_poll');
if (callback) callback();
break;
case 'receiver':
GUI.interval_remove('receiver_poll');
if (callback) callback();
break;
case 'auxiliary_configuration':
GUI.interval_remove('aux_data_poll');
if (callback) callback();
break;
case 'servos':
GUI.interval_remove('servos_data_poll');
if (callback) callback();
break;
case 'gps':
GUI.interval_remove('gps_pull');
if (callback) callback();
break;
case 'motor_outputs':
GUI.interval_remove('motor_poll');
// only enforce mincommand if necessary
if (MOTOR_DATA != undefined) {
var update = false;
for (var i = 0; i < MOTOR_DATA.length; i++) {
if (MOTOR_DATA[i] > MISC.mincommand) {
update = true;
break;
}
}
if (update) {
// send data to mcu
var buffer_out = [];
for (var i = 0; i < 8; i++) {
buffer_out.push(lowByte(MISC.mincommand));
buffer_out.push(highByte(MISC.mincommand));
@ -249,17 +249,17 @@ GUI_control.prototype.tab_switch_cleanup = function(callback) {
case 'sensors':
GUI.interval_kill_all(['port_usage']);
serial.empty_output_buffer();
// sensor data tab uses scrollbars, emptying the content before loading another tab
// prevents scrollbar exposure to any of the tabs while new content is loaded in
$('#content').empty();
if (callback) callback();
break;
case 'cli':
var bufferOut = new ArrayBuffer(5);
var bufView = new Uint8Array(bufferOut);
bufView[0] = 0x65; // e
bufView[1] = 0x78; // x
bufView[2] = 0x69; // i
@ -274,18 +274,18 @@ GUI_control.prototype.tab_switch_cleanup = function(callback) {
GUI.timeout_add('waiting_for_bootup', function() {
CLI_active = false;
CLI_valid = false;
if (callback) callback();
}, 5000); // if we dont allow enough time to reboot, CRC of "first" command sent will fail, keep an eye for this one
});
break;
case 'firmware_flasher':
PortHandler.flush_callbacks();
if (callback) callback();
break;
default:
if (callback) callback();
}

188
js/msp.js
View file

@ -21,7 +21,7 @@ var MSP_codes = {
MSP_WP: 118,
MSP_BOXIDS: 119,
MSP_SERVO_CONF: 120,
MSP_SET_RAW_RC: 200,
MSP_SET_RAW_GPS: 201,
MSP_SET_PID: 202,
@ -36,14 +36,14 @@ var MSP_codes = {
MSP_SET_HEAD: 211,
MSP_SET_SERVO_CONF: 212,
MSP_SET_MOTOR: 214,
// MSP_BIND: 240,
MSP_EEPROM_WRITE: 250,
MSP_DEBUGMSG: 253,
MSP_DEBUG: 254,
// Additional baseflight commands that are not compatible with MultiWii
MSP_UID: 160, // Unique device ID
MSP_ACC_TRIM: 240, // get acc angle trim values
@ -63,29 +63,29 @@ var MSP = {
message_buffer: undefined,
message_buffer_uint8_view: undefined,
message_checksum: 0,
callbacks: [],
packet_error: 0,
callbacks_cleanup: function() {
for (var i = 0; i < this.callbacks.length; i++) {
clearInterval(this.callbacks[i].timer);
}
this.callbacks = [];
},
disconnect_cleanup: function() {
this.state = 0; // reset packet state for "clean" initial entry (this is only required if user hot-disconnects)
this.packet_error = 0; // reset CRC packet error counter for next session
this.callbacks_cleanup();
}
};
MSP.read = function(readInfo) {
var data = new Uint8Array(readInfo.data);
for (var i = 0; i < data.length; i++) {
switch (this.state) {
case 0: // sync char 1
@ -106,24 +106,24 @@ MSP.read = function(readInfo) {
} else { // unknown
message_status = 0;
}
this.state++;
break;
case 3:
this.message_length_expected = data[i];
this.message_checksum = data[i];
// setup arraybuffer
this.message_buffer = new ArrayBuffer(this.message_length_expected);
this.message_buffer_uint8_view = new Uint8Array(this.message_buffer);
this.state++;
break;
case 4:
this.code = data[i];
this.message_checksum ^= data[i];
if (this.message_length_expected != 0) { // standard message
this.state++;
} else { // MSP_ACC_CALIBRATION, etc...
@ -134,7 +134,7 @@ MSP.read = function(readInfo) {
this.message_buffer_uint8_view[this.message_length_received] = data[i];
this.message_checksum ^= data[i];
this.message_length_received++;
if (this.message_length_received >= this.message_length_expected) {
this.state++;
}
@ -145,24 +145,24 @@ MSP.read = function(readInfo) {
this.process_data(this.code, this.message_buffer, this.message_length_expected);
} else {
console.log('code: ' + this.code + ' - crc failed');
this.packet_error++;
$('span.packet-error').html(this.packet_error);
}
// Reset variables
this.message_length_received = 0;
this.state = 0;
this.state = 0;
break;
}
char_counter++;
}
};
MSP.process_data = function(code, message_buffer, message_length) {
var data = new DataView(message_buffer, 0); // DataView (allowing us to view arrayBuffer as struct/union)
switch (code) {
case MSP_codes.MSP_IDENT:
CONFIG.version = parseFloat((data.getUint8(0) / 100).toFixed(2));
@ -176,7 +176,7 @@ MSP.process_data = function(code, message_buffer, message_length) {
CONFIG.activeSensors = data.getUint16(4, 1);
CONFIG.mode = data.getUint32(6, 1);
CONFIG.profile = data.getUint8(10);
sensor_status(CONFIG.activeSensors);
$('span.cycle-time').html(CONFIG.cycleTime);
break;
@ -186,7 +186,7 @@ MSP.process_data = function(code, message_buffer, message_length) {
SENSOR_DATA.accelerometer[0] = data.getInt16(0, 1) / 512;
SENSOR_DATA.accelerometer[1] = data.getInt16(2, 1) / 512;
SENSOR_DATA.accelerometer[2] = data.getInt16(4, 1) / 512;
// properly scaled
SENSOR_DATA.gyroscope[0] = data.getInt16(6, 1) * (4 / 16.4);
SENSOR_DATA.gyroscope[1] = data.getInt16(8, 1) * (4 / 16.4);
@ -201,29 +201,29 @@ MSP.process_data = function(code, message_buffer, message_length) {
var needle = 0;
for (var i = 0; i < 8; i++) {
SERVO_DATA[i] = data.getUint16(needle, 1);
needle += 2;
}
break;
}
break;
case MSP_codes.MSP_MOTOR:
var needle = 0;
for (var i = 0; i < 8; i++) {
MOTOR_DATA[i] = data.getUint16(needle, 1);
needle += 2;
}
break;
}
break;
case MSP_codes.MSP_RC:
RC.roll = data.getUint16(0, 1);
RC.pitch = data.getUint16(2, 1);
RC.yaw = data.getUint16(4, 1);
RC.throttle = data.getUint16(6, 1);
RC.AUX1 = data.getUint16(8, 1);
RC.AUX2 = data.getUint16(10, 1);
RC.AUX3 = data.getUint16(12, 1);
RC.AUX4 = data.getUint16(14, 1);
break;
break;
case MSP_codes.MSP_RAW_GPS:
GPS_DATA.fix = data.getUint8(0);
GPS_DATA.numSat = data.getUint8(1);
@ -232,26 +232,26 @@ MSP.process_data = function(code, message_buffer, message_length) {
GPS_DATA.alt = data.getUint16(10, 1);
GPS_DATA.speed = data.getUint16(12, 1);
GPS_DATA.ground_course = data.getUint16(14, 1);
break;
break;
case MSP_codes.MSP_COMP_GPS:
GPS_DATA.distanceToHome = data.getUint16(0, 1);
GPS_DATA.directionToHome = data.getUint16(2, 1);
GPS_DATA.update = data.getUint8(4);
break;
break;
case MSP_codes.MSP_ATTITUDE:
SENSOR_DATA.kinematicsX = data.getInt16(0, 1) / 10.0;
SENSOR_DATA.kinematicsY = data.getInt16(2, 1) / 10.0;
SENSOR_DATA.kinematicsZ = data.getInt16(4, 1);
break;
break;
case MSP_codes.MSP_ALTITUDE:
SENSOR_DATA.altitude = parseFloat((data.getInt32(0, 1) / 100.0).toFixed(2)); // correct scale factor
break;
break;
case MSP_codes.MSP_ANALOG:
ANALOG.voltage = data.getUint8(0) / 10.0;
ANALOG.power = data.getUint16(1, 1);
ANALOG.rssi = data.getUint16(3, 1);
ANALOG.amperage = data.getUint16(5, 1);
break;
break;
case MSP_codes.MSP_RC_TUNING:
RC_tuning.RC_RATE = parseFloat((data.getUint8(0) / 100).toFixed(2));
RC_tuning.RC_EXPO = parseFloat((data.getUint8(1) / 100).toFixed(2));
@ -260,17 +260,17 @@ MSP.process_data = function(code, message_buffer, message_length) {
RC_tuning.dynamic_THR_PID = parseFloat((data.getUint8(4) / 100).toFixed(2));
RC_tuning.throttle_MID = parseFloat((data.getUint8(5) / 100).toFixed(2));
RC_tuning.throttle_EXPO = parseFloat((data.getUint8(6) / 100).toFixed(2));
break;
break;
case MSP_codes.MSP_PID:
// PID data arrived, we need to scale it and save to appropriate bank / array
for (var i = 0, needle = 0; i < (message_length / 3); i++, needle += 3) {
// main for loop selecting the pid section
// main for loop selecting the pid section
switch (i) {
case 0:
case 1:
case 2:
case 3:
case 7:
case 0:
case 1:
case 2:
case 3:
case 7:
case 8:
case 9:
PIDs[i][0] = data.getUint8(needle) / 10;
@ -282,24 +282,24 @@ MSP.process_data = function(code, message_buffer, message_length) {
PIDs[i][1] = data.getUint8(needle + 1) / 100;
PIDs[i][2] = data.getUint8(needle + 2) / 1000;
break;
case 5:
case 5:
case 6:
PIDs[i][0] = data.getUint8(needle) / 10;
PIDs[i][1] = data.getUint8(needle + 1) / 100;
PIDs[i][2] = data.getUint8(needle + 2) / 1000;
break;
break;
}
}
break;
break;
case MSP_codes.MSP_BOX:
// dump previous data (if there was any)
AUX_CONFIG_values = new Array();
// fill in current data
for (var i = 0; i < data.byteLength; i += 2) { // + 2 because uint16_t = 2 bytes
AUX_CONFIG_values.push(data.getUint16(i, 1));
}
break;
break;
case MSP_codes.MSP_MISC: // 22 bytes
MISC.PowerTrigger1 = data.getInt16(0, 1);
MISC.minthrottle = data.getUint16(2, 1); // 0-2000
@ -313,29 +313,29 @@ MSP.process_data = function(code, message_buffer, message_length) {
MISC.vbatmincellvoltage = data.getUint8(19, 1) / 10; // 10-50
MISC.vbatmaxcellvoltage = data.getUint8(20, 1) / 10; // 10-50
MISC.empty = data.getUint8(21, 1);
break;
break;
case MSP_codes.MSP_MOTOR_PINS:
console.log(data);
break;
break;
case MSP_codes.MSP_BOXNAMES:
AUX_CONFIG = []; // empty the array as new data is coming in
var buff = new Array();
for (var i = 0; i < data.byteLength; i++) {
if (data.getUint8(i) == 0x3B) { // ; (delimeter char)
AUX_CONFIG.push(String.fromCharCode.apply(null, buff)); // convert bytes into ASCII and save as strings
// empty buffer
buff = [];
} else {
buff.push(data.getUint8(i));
}
}
break;
break;
case MSP_codes.MSP_PIDNAMES:
console.log(data);
break;
break;
case MSP_codes.MSP_WP:
console.log(data);
break;
@ -345,43 +345,43 @@ MSP.process_data = function(code, message_buffer, message_length) {
case MSP_codes.MSP_SERVO_CONF:
// drop previous data
SERVO_CONFIG = [];
for (var i = 0; i < 56; i += 7) {
var arr = {
'min': data.getInt16(i, 1),
'max': data.getInt16(i + 2, 1),
'middle': data.getInt16(i + 4, 1),
'min': data.getInt16(i, 1),
'max': data.getInt16(i + 2, 1),
'middle': data.getInt16(i + 4, 1),
'rate': data.getInt8(i + 6)
};
SERVO_CONFIG.push(arr);
}
break;
case MSP_codes.MSP_SET_RAW_RC:
break;
break;
case MSP_codes.MSP_SET_RAW_GPS:
break;
break;
case MSP_codes.MSP_SET_PID:
console.log('PID settings saved');
break;
break;
case MSP_codes.MSP_SET_BOX:
console.log('AUX Configuration saved');
break;
break;
case MSP_codes.MSP_SET_RC_TUNING:
console.log('RC Tuning saved');
break;
break;
case MSP_codes.MSP_ACC_CALIBRATION:
console.log('Accel calibration executed');
break;
break;
case MSP_codes.MSP_MAG_CALIBRATION:
console.log('Mag calibration executed');
break;
case MSP_codes.MSP_SET_MISC:
console.log('MISC Configuration saved');
break;
break;
case MSP_codes.MSP_RESET_CONF:
console.log('Settings Reset');
// With new flight software settings in place, we have to re-pull
// latest values
send_message(MSP_codes.MSP_IDENT, MSP_codes.MSP_IDENT);
@ -390,22 +390,22 @@ MSP.process_data = function(code, message_buffer, message_length) {
send_message(MSP_codes.MSP_RC_TUNING, MSP_codes.MSP_RC_TUNING);
send_message(MSP_codes.MSP_BOXNAMES, MSP_codes.MSP_BOXNAMES);
send_message(MSP_codes.MSP_BOX, MSP_codes.MSP_BOX);
// baseflight specific
send_message(MSP_codes.MSP_UID, MSP_codes.MSP_UID);
send_message(MSP_codes.MSP_ACC_TRIM, MSP_codes.MSP_ACC_TRIM);
break;
break;
case MSP_codes.MSP_SELECT_SETTING:
console.log('Profile selected');
break;
case MSP_codes.MSP_SET_SERVO_CONF:
console.log('Servo Configuration saved');
break;
break;
case MSP_codes.MSP_EEPROM_WRITE:
console.log('Settings Saved in EEPROM');
break;
break;
case MSP_codes.MSP_DEBUGMSG:
break;
break;
case MSP_codes.MSP_DEBUG:
for (var i = 0; i < 4; i++)
SENSOR_DATA.debug[i] = data.getInt16((2 * i), 1);
@ -429,39 +429,39 @@ MSP.process_data = function(code, message_buffer, message_length) {
case MSP_codes.MSP_GPSSVINFO:
if (data.byteLength > 0) {
var numCh = data.getUint8(0);
var needle = 1;
for (var i = 0; i < numCh; i++) {
GPS_DATA.chn[i] = data.getUint8(needle);
GPS_DATA.svid[i] = data.getUint8(needle + 1);
GPS_DATA.quality[i] = data.getUint8(needle + 2);
GPS_DATA.cno[i] = data.getUint8(needle + 3);
needle += 4;
}
}
break;
default:
console.log('Unknown code detected: ' + code);
}
// trigger callbacks, cleanup/remove callback after trigger
for (var i = (this.callbacks.length - 1); i >= 0; i--) { // itterating in reverse because we use .splice which modifies array length
if (this.callbacks[i].code == code) {
// saving current obj for after-callback comparison
var obj = this.callbacks[i];
// remove timeout
clearInterval(obj.timer);
// fire callback
if (obj.callback) obj.callback({'command': code, 'data': data, 'length': message_length});
// remove object from array
// we need to check if the callback object still exists as it could have been touched/moved/removed in callback routine
var index = this.callbacks.indexOf(obj);
if (index > -1) this.callbacks.splice(index, 1);
}
}
@ -470,26 +470,26 @@ MSP.process_data = function(code, message_buffer, message_length) {
function send_message(code, data, callback_sent, callback_msp) {
var bufferOut;
var bufView;
// always reserve 6 bytes for protocol overhead !
if (typeof data === 'object') {
var size = data.length + 6;
var checksum = 0;
bufferOut = new ArrayBuffer(size);
bufView = new Uint8Array(bufferOut);
bufView = new Uint8Array(bufferOut);
bufView[0] = 36; // $
bufView[1] = 77; // M
bufView[2] = 60; // <
bufView[3] = data.length;
bufView[4] = code;
checksum = bufView[3] ^ bufView[4];
for (var i = 0; i < data.length; i++) {
bufView[i + 5] = data[i];
checksum ^= bufView[i + 5];
}
@ -497,7 +497,7 @@ function send_message(code, data, callback_sent, callback_msp) {
} else {
bufferOut = new ArrayBuffer(7);
bufView = new Uint8Array(bufferOut);
bufView[0] = 36; // $
bufView[1] = 77; // M
bufView[2] = 60; // <
@ -514,14 +514,14 @@ function send_message(code, data, callback_sent, callback_msp) {
return false; // skips the code below
}
}
var obj = {'code': code, 'callback': (callback_msp) ? callback_msp : false};
obj.timer = setInterval(function() {
console.log('MSP data request timed-out: ' + code);
serial.send(bufferOut, function(writeInfo) {});
}, 1000); // we should be able to define timeout in the future
MSP.callbacks.push(obj);
serial.send(bufferOut, function(writeInfo) {
@ -529,6 +529,6 @@ function send_message(code, data, callback_sent, callback_msp) {
if (callback_sent) callback_sent();
}
});
return true;
}

View file

@ -1,7 +1,7 @@
function port_handler() {
this.main_timeout_reference;
this.initial_ports = false;
this.port_detected_callbacks = [];
this.port_removed_callbacks = [];
}
@ -13,12 +13,12 @@ port_handler.prototype.initialize = function() {
port_handler.prototype.check = function() {
var self = this;
serial.getDevices(function(current_ports) {
// port got removed or initial_ports wasn't initialized yet
if (self.array_difference(self.initial_ports, current_ports).length > 0 || !self.initial_ports) {
var removed_ports = self.array_difference(self.initial_ports, current_ports);
if (self.initial_ports != false) {
if (removed_ports.length > 1) {
console.log('PortHandler - Removed: ' + removed_ports);
@ -26,7 +26,7 @@ port_handler.prototype.check = function() {
console.log('PortHandler - Removed: ' + removed_ports[0]);
}
}
// disconnect "UI" if necessary
// Keep in mind that this routine can not fire during atmega32u4 reboot procedure !!!
if (GUI.connected_to) {
@ -36,35 +36,35 @@ port_handler.prototype.check = function() {
}
}
}
self.update_port_select(current_ports);
// trigger callbacks (only after initialization)
if (self.initial_ports) {
for (var i = (self.port_removed_callbacks.length - 1); i >= 0; i--) {
var obj = self.port_removed_callbacks[i];
// remove timeout
clearTimeout(obj.timer);
// trigger callback
obj.code(removed_ports);
// remove object from array
var index = self.port_removed_callbacks.indexOf(obj);
if (index > -1) self.port_removed_callbacks.splice(index, 1);
}
}
// auto-select last used port (only during initialization)
if (!self.initial_ports) {
chrome.storage.local.get('last_used_port', function(result) {
// if last_used_port was set, we try to select it
if (result.last_used_port) {
if (result.last_used_port) {
current_ports.forEach(function(port) {
if (port == result.last_used_port) {
console.log('Selecting last used port: ' + result.last_used_port);
$('div#port-picker .port select').val(result.last_used_port);
}
});
@ -73,7 +73,7 @@ port_handler.prototype.check = function() {
}
});
}
if (!self.initial_ports) {
// initialize
self.initial_ports = current_ports;
@ -83,26 +83,26 @@ port_handler.prototype.check = function() {
}
}
}
// new port detected
var new_ports = self.array_difference(current_ports, self.initial_ports);
if (new_ports.length) {
if (new_ports.length > 1) {
console.log('PortHandler - Found: ' + new_ports);
} else {
console.log('PortHandler - Found: ' + new_ports[0]);
}
self.update_port_select(current_ports);
// select / highlight new port, if connected -> select connected port
if (!GUI.connected_to) {
$('div#port-picker .port select').val(new_ports[0]);
} else {
} else {
$('div#port-picker .port select').val(GUI.connected_to);
}
// start connect procedure (if statement is valid)
if (GUI.auto_connect && !GUI.connecting_to && !GUI.connected_to) {
// we need firmware flasher protection over here
@ -112,25 +112,25 @@ port_handler.prototype.check = function() {
}, 50); // small timeout so we won't get any nasty connect errors due to system initializing the bus
}
}
// trigger callbacks
for (var i = (self.port_detected_callbacks.length - 1); i >= 0; i--) {
var obj = self.port_detected_callbacks[i];
// remove timeout
clearTimeout(obj.timer);
// trigger callback
obj.code(new_ports);
// remove object from array
var index = self.port_detected_callbacks.indexOf(obj);
if (index > -1) self.port_detected_callbacks.splice(index, 1);
}
self.initial_ports = current_ports;
}
self.main_timeout_reference = setTimeout(function() {
self.check();
}, 250);
@ -139,27 +139,27 @@ port_handler.prototype.check = function() {
port_handler.prototype.update_port_select = function(ports) {
$('div#port-picker .port select').html(''); // drop previous one
if (ports.length > 0) {
for (var i = 0; i < ports.length; i++) {
$('div#port-picker .port select').append($("<option/>", {value: ports[i], text: ports[i]}));
}
} else {
$('div#port-picker .port select').append($("<option/>", {value: 0, text: 'No Ports'}));
}
}
};
port_handler.prototype.port_detected = function(name, code, timeout, ignore_timeout) {
var self = this;
var obj = {'name': name, 'code': code, 'timeout': (timeout) ? timeout : 10000};
if (!ignore_timeout) {
obj.timer = setTimeout(function() {
console.log('PortHandler - timeout - ' + obj.name);
// trigger callback
code(false);
// remove object from array
var index = self.port_detected_callbacks.indexOf(obj);
if (index > -1) self.port_detected_callbacks.splice(index, 1);
@ -168,7 +168,7 @@ port_handler.prototype.port_detected = function(name, code, timeout, ignore_time
obj.timer = false;
obj.timeout = false;
}
this.port_detected_callbacks.push(obj);
return obj;
@ -177,14 +177,14 @@ port_handler.prototype.port_detected = function(name, code, timeout, ignore_time
port_handler.prototype.port_removed = function(name, code, timeout, ignore_timeout) {
var self = this;
var obj = {'name': name, 'code': code, 'timeout': (timeout) ? timeout : 10000};
if (!ignore_timeout) {
obj.timer = setTimeout(function() {
console.log('PortHandler - timeout - ' + obj.name);
// trigger callback
code(false);
// remove object from array
var index = self.port_removed_callbacks.indexOf(obj);
if (index > -1) self.port_removed_callbacks.splice(index, 1);
@ -193,44 +193,44 @@ port_handler.prototype.port_removed = function(name, code, timeout, ignore_timeo
obj.timer = false;
obj.timeout = false;
}
this.port_removed_callbacks.push(obj);
return obj;
};
// accepting single level array with "value" as key
port_handler.prototype.array_difference = function(firstArray, secondArray) {
var cloneArray = [];
// create hardcopy
for (var i = 0; i < firstArray.length; i++) {
cloneArray.push(firstArray[i]);
}
for (var i = 0; i < secondArray.length; i++) {
if (cloneArray.indexOf(secondArray[i]) != -1) {
cloneArray.splice(cloneArray.indexOf(secondArray[i]), 1);
}
}
return cloneArray;
};
port_handler.prototype.flush_callbacks = function() {
var killed = 0;
for (var i = this.port_detected_callbacks.length - 1; i >= 0; i--) {
for (var i = this.port_detected_callbacks.length - 1; i >= 0; i--) {
if (this.port_detected_callbacks[i].timer) clearTimeout(this.port_detected_callbacks[i].timer);
this.port_detected_callbacks.splice(i, 1);
killed++;
}
for (var i = this.port_removed_callbacks.length - 1; i >= 0; i--) {
if (this.port_removed_callbacks[i].timer) clearTimeout(this.port_removed_callbacks[i].timer);
this.port_removed_callbacks.splice(i, 1);
killed++;
}

View file

@ -2,25 +2,25 @@ var serial = {
connectionId: -1,
bytes_received: 0,
bytes_sent: 0,
transmitting: false,
output_buffer: [],
connect: function(path, options, callback) {
var self = this;
chrome.serial.connect(path, options, function(connectionInfo) {
if (connectionInfo !== undefined) {
self.connectionId = connectionInfo.connectionId;
self.bytes_received = 0;
self.bytes_sent = 0;
self.onReceive.addListener(function log_bytes_received(info) {
self.bytes_received += info.data.byteLength;
});
console.log('SERIAL: Connection opened with ID: ' + connectionInfo.connectionId + ', Baud: ' + connectionInfo.bitrate);
callback(connectionInfo);
} else {
console.log('SERIAL: Failed to open serial port');
@ -30,25 +30,25 @@ var serial = {
},
disconnect: function(callback) {
var self = this;
self.empty_output_buffer();
// remove listeners
for (var i = (self.onReceive.listeners.length - 1); i >= 0; i--) {
self.onReceive.removeListener(self.onReceive.listeners[i]);
}
chrome.serial.disconnect(this.connectionId, function(result) {
if (result) {
console.log('SERIAL: Connection with ID: ' + self.connectionId + ' closed');
} else {
console.log('SERIAL: Failed to close connection with ID: ' + self.connectionId + ' closed');
}
console.log('SERIAL: Statistics - Sent: ' + self.bytes_sent + ' bytes, Received: ' + self.bytes_received + ' bytes');
self.connectionId = -1;
callback(result);
});
},
@ -58,7 +58,7 @@ var serial = {
devices_array.forEach(function(device) {
devices.push(device.path);
});
callback(devices);
});
},
@ -68,54 +68,54 @@ var serial = {
send: function(data, callback) {
var self = this;
self.output_buffer.push({'data': data, 'callback': callback});
if (!self.transmitting) {
self.transmitting = true;
var sending = function() {
// store inside separate variables in case array gets destroyed
var data = self.output_buffer[0].data;
var callback = self.output_buffer[0].callback;
chrome.serial.send(self.connectionId, data, function(sendInfo) {
callback(sendInfo);
self.output_buffer.shift();
self.bytes_sent += sendInfo.bytesSent;
if (self.output_buffer.length) {
// keep the buffer withing reasonable limits
while (self.output_buffer.length > 500) {
self.output_buffer.pop();
}
sending();
} else {
self.transmitting = false;
}
});
};
sending();
}
},
onReceive: {
listeners: [],
addListener: function(function_reference) {
var listener = chrome.serial.onReceive.addListener(function_reference);
this.listeners.push(function_reference);
},
removeListener: function(function_reference) {
removeListener: function(function_reference) {
for (var i = (this.listeners.length - 1); i >= 0; i--) {
if (this.listeners[i] == function_reference) {
chrome.serial.onReceive.removeListener(function_reference);
this.listeners.splice(i, 1);
break;
}
}
}
}
},
empty_output_buffer: function() {

View file

@ -2,55 +2,55 @@ var configuration_received = false;
var CLI_active = false;
var CLI_valid = false;
$(document).ready(function() {
$(document).ready(function() {
$('div#port-picker a.connect').click(function() {
if (GUI.connect_lock != true) { // GUI control overrides the user control
var clicks = $(this).data('clicks');
var selected_port = String($('div#port-picker .port select').val());
var selected_baud = parseInt($('div#port-picker #baud').val());
if (selected_port != '0') {
if (!clicks) {
console.log('Connecting to: ' + selected_port);
GUI.connecting_to = selected_port;
// lock port select & baud while we are connecting / connected
$('div#port-picker #port, div#port-picker #baud, div#port-picker #delay').prop('disabled', true);
$('div#port-picker a.connect').text('Connecting');
$('div#port-picker a.connect').text('Connecting');
serial.connect(selected_port, {bitrate: selected_baud}, onOpen);
} else {
// Disable any active "data pulling" timer
GUI.interval_kill_all();
GUI.tab_switch_cleanup();
GUI.timeout_remove('connecting');
serial.disconnect(onClosed);
GUI.connected_to = false;
// Reset various UI elements
$('span.port-usage').html('0%');
$('.software-version').html('0.0');
$('span.cycle-time').html('0');
MSP.disconnect_cleanup();
configuration_received = false; // reset valid config received variable (used to block tabs while not connected properly)
// unlock port select & baud
$('div#port-picker #port').prop('disabled', false);
if (!GUI.auto_connect) $('div#port-picker #baud').prop('disabled', false);
$(this).text('Connect');
$(this).removeClass('active');
sensor_status(sensors_detected = 0); // reset active sensor indicators
$('#tabs > ul li').removeClass('active'); // de-select any selected tabs
tab_initialize_default();
}
$(this).data("clicks", !clicks);
}
}
@ -61,62 +61,62 @@ $(document).ready(function() {
if (typeof result.auto_connect === 'undefined') {
// auto_connect wasn't saved yet, save and push true to the GUI
GUI.auto_connect = true;
$('input.auto_connect').prop('checked', true);
$('input.auto_connect, span.auto_connect').prop('title', 'Auto-Connect: Enabled - Configurator automatically tries to connect when new port is detected');
$('select#baud').val(115200).prop('disabled', true);
// save
chrome.storage.local.set({'auto_connect': true});
} else {
if (result.auto_connect) {
if (result.auto_connect) {
// enabled by user
GUI.auto_connect = true;
$('input.auto_connect').prop('checked', true);
$('input.auto_connect, span.auto_connect').prop('title', 'Auto-Connect: Enabled - Configurator automatically tries to connect when new serial port is detected');
$('select#baud').val(115200).prop('disabled', true);
} else {
} else {
// disabled by user
GUI.auto_connect = false;
$('input.auto_connect').prop('checked', false);
$('input.auto_connect, span.auto_connect').prop('title', 'Auto-Connect: Disabled - User needs to select the correct serial port and click "Connect" button on its own');
}
}
// bind UI hook to auto-connect checkbos
$('input.auto_connect').change(function() {
GUI.auto_connect = $(this).is(':checked');
// update title/tooltip
if (GUI.auto_connect) {
$('input.auto_connect, span.auto_connect').prop('title', 'Auto-Connect: Enabled - Configurator automatically tries to connect when new port is detected');
$('select#baud').val(115200).prop('disabled', true);
} else {
$('input.auto_connect, span.auto_connect').prop('title', 'Auto-Connect: Disabled - User needs to select the correct serial port and click "Connect" button on its own');
if (!GUI.connected_to && !GUI.connecting_to) $('select#baud').prop('disabled', false);
}
chrome.storage.local.set({'auto_connect': GUI.auto_connect});
});
});
PortHandler.initialize();
});
});
function onOpen(openInfo) {
function onOpen(openInfo) {
if (openInfo) {
// update connected_to
GUI.connected_to = GUI.connecting_to;
// reset connecting_to
GUI.connecting_to = false;
GUI.log('Serial port <span style="color: green">successfully</span> opened with ID: ' + openInfo.connectionId);
// save selected port with chrome.storage if the port differs
chrome.storage.local.get('last_used_port', function(result) {
if (typeof result.last_used_port != 'undefined') {
@ -138,12 +138,12 @@ function onOpen(openInfo) {
serial.onReceive.addListener(read_serial);
GUI.interval_add('port_usage', port_usage, 1000, true);
// disconnect after 10 seconds with error if we don't get IDENT data
GUI.timeout_add('connecting', function() {
if (!configuration_received) {
GUI.log('No configuration received within <span style="color: red">10 seconds</span>, communication <span style="color: red">failed</span>');
$('div#port-picker a.connect').click(); // disconnect
}
}, 10000);
@ -153,11 +153,11 @@ function onOpen(openInfo) {
GUI.log('Unique device ID <span style="color: green">received</span> - <strong>0x' + CONFIG.uid[0].toString(16) + CONFIG.uid[1].toString(16) + CONFIG.uid[2].toString(16) + '</strong>');
send_message(MSP_codes.MSP_IDENT, MSP_codes.MSP_IDENT, false, function() {
GUI.timeout_remove('connecting'); // kill connecting timer
if (CONFIG.version >= firmware_version_accepted) {
// Update UI elements that doesn't need consistent refreshing
$('.software-version').html(CONFIG.version);
configuration_received = true;
$('div#port-picker a.connect').text('Disconnect').addClass('active');
$('#tabs li a:first').click();
@ -170,13 +170,13 @@ function onOpen(openInfo) {
} else {
console.log('Failed to open serial port');
GUI.log('Failed to open serial port', 'red');
$('div#port-picker a.connect').text('Connect');
$('div#port-picker a.connect').removeClass('active');
$('div#port-picker a.connect').removeClass('active');
// unlock port select & baud
$('div#port-picker #port, div#port-picker #baud, div#port-picker #delay').prop('disabled', false);
// reset data
$('div#port-picker a.connect').data("clicks", false);
}
@ -187,7 +187,7 @@ function onClosed(result) {
GUI.log('Serial port <span style="color: green">successfully</span> closed');
} else { // Something went wrong
GUI.log('<span style="color: red">Failed</span> to close serial port');
}
}
}
function read_serial(info) {
@ -199,7 +199,7 @@ function read_serial(info) {
}
function port_usage() {
var port_usage = (char_counter * 10 / parseInt($('div#port-picker #baud').val())) * 100;
var port_usage = (char_counter * 10 / parseInt($('div#port-picker #baud').val())) * 100;
$('span.port-usage').html(parseInt(port_usage) + '%');
// reset counter
@ -211,11 +211,11 @@ function sensor_status(sensors_detected) {
if (typeof sensor_status.previous_sensors_detected == 'undefined') {
sensor_status.previous_sensors_detected = 0;
}
// update UI (if necessary)
if (sensor_status.previous_sensors_detected != sensors_detected) {
var e_sensor_status = $('div#sensor-status');
if (bit_check(sensors_detected, 0)) { // Gyroscope & accel detected
$('.gyro', e_sensor_status).addClass('on');
$('.accel', e_sensor_status).addClass('on');
@ -228,26 +228,26 @@ function sensor_status(sensors_detected) {
$('.baro', e_sensor_status).addClass('on');
} else {
$('.baro', e_sensor_status).removeClass('on');
}
}
if (bit_check(sensors_detected, 2)) { // Magnetometer detected
$('.mag', e_sensor_status).addClass('on');
} else {
$('.mag', e_sensor_status).removeClass('on');
}
}
if (bit_check(sensors_detected, 3)) { // GPS detected
$('.gps', e_sensor_status).addClass('on');
} else {
$('.gps', e_sensor_status).removeClass('on');
}
}
if (bit_check(sensors_detected, 4)) { // Sonar detected
$('.sonar', e_sensor_status).addClass('on');
} else {
$('.sonar', e_sensor_status).removeClass('on');
}
// set current value
sensor_status.previous_sensors_detected = sensors_detected;
}

View file

@ -1,4 +1,4 @@
/*
/*
STM32 F103 serial bus seems to properly initialize with quite a huge auto-baud range
From 921600 down to 1200, i don't recommend getting any lower then that
Official "specs" are from 115200 to 1200
@ -7,20 +7,20 @@
var STM32_protocol = function() {
this.hex; // ref
this.verify_hex;
this.receive_buffer;
this.bytes_to_read = 0; // ref
this.read_callback; // ref
this.upload_time_start;
this.upload_process_alive;
this.status = {
ACK: 0x79, // y
NACK: 0x1F
};
this.command = {
get: 0x00, // Gets the version and the allowed commands supported by the current version of the bootloader
get_ver_r_protect_s: 0x01, // Gets the bootloader version and the Read Protection status of the Flash memory
@ -35,7 +35,7 @@ var STM32_protocol = function() {
readout_protect: 0x82, // Enables the read protection
readout_unprotect: 0x92 // Disables the read protection
};
// Erase (x043) and Extended Erase (0x44) are exclusive. A device may support either the Erase command or the Extended Erase command but not both.
};
@ -48,14 +48,14 @@ STM32_protocol.prototype.GUI_status = function(string) {
STM32_protocol.prototype.connect = function(hex) {
var self = this;
self.hex = hex;
var selected_port = String($('div#port-picker .port select').val());
var baud = parseInt($('div#port-picker #baud').val());
if (selected_port != '0') {
// popular choices - 921600, 460800, 256000, 230400, 153600, 128000, 115200, 57600, 38400, 28800, 19200
var flashing_bitrate;
switch (GUI.operating_system) {
case 'Windows':
flashing_bitrate = 921600;
@ -68,11 +68,11 @@ STM32_protocol.prototype.connect = function(hex) {
case 'UNIX':
flashing_bitrate = 921600;
break;
default:
flashing_bitrate = 115200;
}
if (!$('input.updating').is(':checked')) {
serial.connect(selected_port, {bitrate: baud}, function(openInfo) {
if (openInfo) {
@ -80,17 +80,17 @@ STM32_protocol.prototype.connect = function(hex) {
// we are connected, disabling connect button in the UI
GUI.connect_lock = true;
var bufferOut = new ArrayBuffer(1);
var bufferView = new Uint8Array(bufferOut);
bufferView[0] = 0x52;
serial.send(bufferOut, function() {
serial.disconnect(function(result) {
if (result) {
if (result) {
serial.connect(selected_port, {bitrate: flashing_bitrate, parityBit: 'even', stopBits: 'one'}, function(openInfo) {
if (openInfo) {
if (openInfo) {
self.initialize();
} else {
GUI.log('<span style="color: red">Failed</span> to open serial port');
@ -107,10 +107,10 @@ STM32_protocol.prototype.connect = function(hex) {
});
} else {
serial.connect(selected_port, {bitrate: flashing_bitrate, parityBit: 'even', stopBits: 'one'}, function(openInfo) {
if (openInfo) {
if (openInfo) {
// we are connected, disabling connect button in the UI
GUI.connect_lock = true;
self.initialize();
} else {
GUI.log('<span style="color: red">Failed</span> to open serial port');
@ -126,14 +126,14 @@ STM32_protocol.prototype.connect = function(hex) {
// initialize certain variables and start timers that oversee the communication
STM32_protocol.prototype.initialize = function() {
var self = this;
// reset and set some variables before we start
// reset and set some variables before we start
self.receive_buffer = [];
self.verify_hex = [];
self.upload_time_start = microtime();
self.upload_process_alive = false;
// reset progress bar to initial state
self.progress_bar_e = $('.progress');
self.progress_bar_e.val(0);
@ -142,42 +142,42 @@ STM32_protocol.prototype.initialize = function() {
serial.onReceive.addListener(function(info) {
self.read(info);
});
GUI.interval_add('STM32_timeout', function() {
if (self.upload_process_alive) { // process is running
self.upload_process_alive = false;
} else {
console.log('STM32 - timed out, programming failed ...');
STM32.GUI_status('STM32 - timed out, programming: <strong style="color: red">FAILED</strong>');
// protocol got stuck, clear timer and disconnect
GUI.interval_remove('STM32_timeout');
// exit
self.upload_procedure(99);
}
}, 1000);
self.upload_procedure(1);
};
// no input parameters
// this method should be executed every 1 ms via interval timer
STM32_protocol.prototype.read = function(readInfo) {
STM32_protocol.prototype.read = function(readInfo) {
// routine that fills the buffer
var data = new Uint8Array(readInfo.data);
for (var i = 0; i < data.length; i++) {
this.receive_buffer.push(data[i]);
this.receive_buffer.push(data[i]);
}
// routine that fetches data from buffer if statement is true
if (this.receive_buffer.length >= this.bytes_to_read && this.bytes_to_read != 0) {
var data = this.receive_buffer.slice(0, this.bytes_to_read); // bytes requested
this.receive_buffer.splice(0, this.bytes_to_read); // remove read bytes
this.bytes_to_read = 0; // reset trigger
this.read_callback(data);
}
};
@ -188,7 +188,7 @@ STM32_protocol.prototype.retrieve = function(n_bytes, callback) {
// data that we need are there, process immediately
var data = this.receive_buffer.slice(0, n_bytes);
this.receive_buffer.splice(0, n_bytes); // remove read bytes
callback(data);
} else {
// still waiting for data, add callback
@ -203,38 +203,38 @@ STM32_protocol.prototype.retrieve = function(n_bytes, callback) {
STM32_protocol.prototype.send = function(Array, bytes_to_read, callback) {
// flip flag
this.upload_process_alive = true;
var bufferOut = new ArrayBuffer(Array.length);
var bufferView = new Uint8Array(bufferOut);
// set Array values inside bufferView (alternative to for loop)
bufferView.set(Array);
// update references
this.bytes_to_read = bytes_to_read;
this.read_callback = callback;
// empty receive buffer before next command is out
this.receive_buffer = [];
// send over the actual data
serial.send(bufferOut, function(writeInfo) {});
serial.send(bufferOut, function(writeInfo) {});
};
// val = single byte to be verified
// val = single byte to be verified
// data = response of n bytes from mcu (array)
// result = true/false
STM32_protocol.prototype.verify_response = function(val, data) {
if (val != data[0]) {
console.log('STM32 Communication failed, wrong response, expected: ' + val + ' received: ' + data[0]);
STM32.GUI_status('STM32 Communication <span style="color: red">failed</span>, wrong response, expected: ' + val + ' received: ' + data[0]);
// disconnect
this.upload_procedure(99);
return false;
}
return true;
};
@ -242,7 +242,7 @@ STM32_protocol.prototype.verify_response = function(val, data) {
// result = true/false
STM32_protocol.prototype.verify_chip_signature = function(signature) {
var available_flash_size = 0;
switch (signature) {
case 0x412: // not tested
console.log('Chip recognized as F1 Low-density');
@ -297,19 +297,19 @@ STM32_protocol.prototype.verify_chip_signature = function(signature) {
console.log('Chip recognized as F3 STM32F30xxx, STM32F31xxx');
break;
}
if (available_flash_size > 0) {
if (this.hex.bytes_total < available_flash_size) {
return true;
} else {
console.log('Supplied hex is bigger then flash available on the chip, HEX: ' + this.hex.bytes_total + ' bytes, limit = ' + available_flash_size + ' bytes');
return false;
}
}
}
console.log('Chip NOT recognized: ' + signature);
return false;
};
@ -323,16 +323,16 @@ STM32_protocol.prototype.verify_flash = function(first_array, second_array) {
return false;
}
}
console.log('Verification successful, matching: ' + first_array.length + ' bytes');
return true;
};
// step = value depending on current state of upload_procedure
STM32_protocol.prototype.upload_procedure = function(step) {
var self = this;
switch (step) {
case 1:
// initialize serial interface on the MCU side, auto baud rate settings
@ -342,18 +342,18 @@ STM32_protocol.prototype.upload_procedure = function(step) {
if (reply[0] == 0x7F || reply[0] == self.status.ACK || reply[0] == self.status.NACK) {
GUI.interval_remove('stm32_initialize_mcu');
console.log('STM32 - Serial interface initialized on the MCU side');
// proceed to next step
self.upload_procedure(2);
} else {
GUI.interval_remove('stm32_initialize_mcu');
STM32.GUI_status('STM32 Communication with bootloader <span style="color: red">failed</span>');
// disconnect
self.upload_procedure(99);
}
});
if (send_counter++ > 3) {
// stop retrying, its too late to get any response from MCU
GUI.interval_remove('stm32_initialize_mcu');
@ -366,7 +366,7 @@ STM32_protocol.prototype.upload_procedure = function(step) {
if (self.verify_response(self.status.ACK, data)) {
self.retrieve(data[1] + 1 + 1, function(data) { // data[1] = number of bytes that will follow [ 1 except current and ACKs]
console.log('STM32 - Bootloader version: ' + (parseInt(data[0].toString(16)) / 10).toFixed(1)); // convert dec to hex, hex to dec and add floating point
// proceed to next step
self.upload_procedure(3);
});
@ -380,7 +380,7 @@ STM32_protocol.prototype.upload_procedure = function(step) {
self.retrieve(data[1] + 1 + 1, function(data) { // data[1] = number of bytes that will follow [ 1 (N = 1 for STM32), except for current byte and ACKs]
var signature = (data[0] << 8) | data[1];
console.log('STM32 - Signature: 0x' + signature.toString(16)); // signature in hex representation
if (self.verify_chip_signature(signature)) {
// proceed to next step
self.upload_procedure(4);
@ -396,7 +396,7 @@ STM32_protocol.prototype.upload_procedure = function(step) {
// erase memory
console.log('Executing global chip erase');
STM32.GUI_status('Erasing');
self.send([self.command.erase, 0xBC], 1, function(reply) { // 0x43 ^ 0xFF
if (self.verify_response(self.status.ACK, reply)) {
self.send([0xFF, 0x00], 1, function(reply) {
@ -404,9 +404,9 @@ STM32_protocol.prototype.upload_procedure = function(step) {
console.log('Erasing: done');
console.log('Writing data ...');
STM32.GUI_status('<span style="color: green">Flashing ...</span>');
// proceed to next step
self.upload_procedure(5);
self.upload_procedure(5);
}
});
}
@ -417,36 +417,36 @@ STM32_protocol.prototype.upload_procedure = function(step) {
var blocks = self.hex.data.length - 1;
var flashing_block = 0;
var address = self.hex.data[flashing_block].address;
var bytes_flashed = 0;
var bytes_flashed_total = 0; // used for progress bar
var write = function() {
if (bytes_flashed < self.hex.data[flashing_block].bytes) {
var bytes_to_write = ((bytes_flashed + 128) <= self.hex.data[flashing_block].bytes) ? 128 : (self.hex.data[flashing_block].bytes - bytes_flashed);
// console.log('STM32 - Writing to: 0x' + address.toString(16) + ', ' + bytes_to_write + ' bytes');
self.send([self.command.write_memory, 0xCE], 1, function(reply) { // 0x31 ^ 0xFF
if (self.verify_response(self.status.ACK, reply)) {
// address needs to be transmitted as 32 bit integer, we need to bit shift each byte out and then calculate address checksum
var address_arr = [(address >> 24), (address >> 16), (address >> 8), address];
var address_checksum = address_arr[0] ^ address_arr[1] ^ address_arr[2] ^ address_arr[3];
self.send([address_arr[0], address_arr[1], address_arr[2], address_arr[3], address_checksum], 1, function(reply) { // write start address + checksum
if (self.verify_response(self.status.ACK, reply)) {
var array_out = new Array(bytes_to_write + 2); // 2 byte overhead [N, ...., checksum]
array_out[0] = bytes_to_write - 1; // number of bytes to be written (to write 128 bytes, N must be 127, to write 256 bytes, N must be 255)
var checksum = array_out[0];
for (var i = 0; i < bytes_to_write; i++) {
array_out[i + 1] = self.hex.data[flashing_block].data[bytes_flashed]; // + 1 because of the first byte offset
checksum ^= self.hex.data[flashing_block].data[bytes_flashed];
bytes_flashed++;
}
array_out[array_out.length - 1] = checksum; // checksum (last byte in the array_out array)
address += bytes_to_write;
bytes_flashed_total += bytes_to_write
@ -454,7 +454,7 @@ STM32_protocol.prototype.upload_procedure = function(step) {
if (self.verify_response(self.status.ACK, reply)) {
// update progress bar
self.progress_bar_e.val(bytes_flashed_total / (self.hex.bytes_total * 2) * 100);
// flash another page
write();
}
@ -467,23 +467,23 @@ STM32_protocol.prototype.upload_procedure = function(step) {
// move to another block
if (flashing_block < blocks) {
flashing_block++;
address = self.hex.data[flashing_block].address;
bytes_flashed = 0;
write();
} else {
// all blocks flashed
console.log('Writing: done');
console.log('Verifying data ...');
STM32.GUI_status('<span style="color: green">Verifying ...</span>');
// proceed to next step
self.upload_procedure(6);
}
}
};
// start writing
write();
break;
@ -492,44 +492,44 @@ STM32_protocol.prototype.upload_procedure = function(step) {
var blocks = self.hex.data.length - 1;
var reading_block = 0;
var address = self.hex.data[reading_block].address;
var bytes_verified = 0;
var bytes_verified_total = 0; // used for progress bar
// initialize arrays
for (var i = 0; i <= blocks; i++) {
self.verify_hex.push([]);
}
var reading = function() {
if (bytes_verified < self.hex.data[reading_block].bytes) {
var bytes_to_read = ((bytes_verified + 128) <= self.hex.data[reading_block].bytes) ? 128 : (self.hex.data[reading_block].bytes - bytes_verified);
// console.log('STM32 - Reading from: 0x' + address.toString(16) + ', ' + bytes_to_read + ' bytes');
self.send([self.command.read_memory, 0xEE], 1, function(reply) { // 0x11 ^ 0xFF
if (self.verify_response(self.status.ACK, reply)) {
var address_arr = [(address >> 24), (address >> 16), (address >> 8), address];
var address_checksum = address_arr[0] ^ address_arr[1] ^ address_arr[2] ^ address_arr[3];
self.send([address_arr[0], address_arr[1], address_arr[2], address_arr[3], address_checksum], 1, function(reply) { // read start address + checksum
if (self.verify_response(self.status.ACK, reply)) {
var bytes_to_read_n = bytes_to_read - 1;
self.send([bytes_to_read_n, (~bytes_to_read_n) & 0xFF], 1, function(reply) { // bytes to be read + checksum XOR(complement of bytes_to_read_n)
if (self.verify_response(self.status.ACK, reply)) {
self.retrieve(bytes_to_read, function(data) {
for (var i = 0; i < data.length; i++) {
self.verify_hex[reading_block].push(data[i]);
}
address += bytes_to_read;
bytes_verified += bytes_to_read;
bytes_verified_total += bytes_to_read;
// update progress bar
self.progress_bar_e.val((self.hex.bytes_total + bytes_verified_total) / (self.hex.bytes_total * 2) * 100);
self.progress_bar_e.val((self.hex.bytes_total + bytes_verified_total) / (self.hex.bytes_total * 2) * 100);
// verify another page
reading();
});
@ -543,44 +543,44 @@ STM32_protocol.prototype.upload_procedure = function(step) {
// move to another block
if (reading_block < blocks) {
reading_block++;
address = self.hex.data[reading_block].address;
bytes_verified = 0;
reading();
} else {
// all blocks read, verify
var verify = true;
for (var i = 0; i <= blocks; i++) {
verify = self.verify_flash(self.hex.data[i].data, self.verify_hex[i]);
if (!verify) break;
}
if (verify) {
console.log('Programming: SUCCESSFUL');
STM32.GUI_status('Programming: <strong style="color: green">SUCCESSFUL</strong>');
// update progress bar
self.progress_bar_e.addClass('valid');
// proceed to next step
self.upload_procedure(7);
self.upload_procedure(7);
} else {
console.log('Programming: FAILED');
STM32.GUI_status('Programming: <strong style="color: red">FAILED</strong>');
// update progress bar
self.progress_bar_e.addClass('invalid');
// disconnect
self.upload_procedure(99);
self.upload_procedure(99);
}
}
}
};
// start reading
reading();
break;
@ -594,7 +594,7 @@ STM32_protocol.prototype.upload_procedure = function(step) {
var gt_address = 0x8000000;
var address = [(gt_address >> 24), (gt_address >> 16), (gt_address >> 8), gt_address];
var address_checksum = address[0] ^ address[1] ^ address[2] ^ address[3];
self.send([address[0], address[1], address[2], address[3], address_checksum], 1, function(reply) {
if (self.verify_response(self.status.ACK, reply)) {
// disconnect
@ -607,15 +607,15 @@ STM32_protocol.prototype.upload_procedure = function(step) {
case 99:
// disconnect
GUI.interval_remove('STM32_timeout'); // stop STM32 timeout timer (everything is finished now)
console.log('Script finished after: ' + (microtime() - self.upload_time_start).toFixed(4) + ' seconds');
// close connection
serial.disconnect(function(result) {
if (result) { // All went as expected
} else { // Something went wrong
}
// unlocking connect button
GUI.connect_lock = false;
});

View file

@ -3,24 +3,24 @@
// if hex file wasn't valid (crc check failed on any of the lines), result will be false
function read_hex_file(data) {
data = data.split("\n");
// check if there is an empty line in the end of hex file, if there is, remove it
if (data[data.length - 1] == "") {
data.pop();
}
var hexfile_valid = true; // if any of the crc checks failed, this variable flips to false
var result = {
data: [],
end_of_file: false,
bytes_total: 0,
start_linear_address: 0
};
var extended_linear_address = 0;
var next_address = 0;
for (var i = 0; i < data.length && hexfile_valid; i++) {
// each byte is represnted by two chars
var byte_count = parseInt(data[i].substr(1, 2), 16);
@ -28,33 +28,33 @@ function read_hex_file(data) {
var record_type = parseInt(data[i].substr(7, 2), 16);
var content = data[i].substr(9, byte_count * 2); // still in string format
var checksum = parseInt(data[i].substr(9 + byte_count * 2, 2), 16); // (this is a 2's complement value)
switch (record_type) {
case 0x00: // data record
case 0x00: // data record
if (address != next_address || next_address == 0) {
result.data.push({'address': extended_linear_address + address, 'bytes': 0, 'data': []});
}
// store address for next comparison
next_address = address + byte_count;
// process data
var crc = byte_count + parseInt(data[i].substr(3, 2), 16) + parseInt(data[i].substr(5, 2), 16) + record_type;
for (var needle = 0; needle < byte_count * 2; needle += 2) { // * 2 because of 2 hex chars per 1 byte
var num = parseInt(content.substr(needle, 2), 16); // get one byte in hex and convert it to decimal
var data_block = result.data.length - 1;
result.data[data_block].data.push(num);
result.data[data_block].bytes++;
result.data[data_block].bytes++;
crc += num;
result.bytes_total++;
}
// change crc to 2's complement
crc = (~crc + 1) & 0xFF;
// verify
// verify
if (crc != checksum) {
hexfile_valid = false;
}
@ -82,7 +82,7 @@ function read_hex_file(data) {
break;
}
}
if (result.end_of_file && hexfile_valid) {
postMessage(result);
} else {
@ -98,11 +98,11 @@ function microtime() {
onmessage = function(event) {
var time_parsing_start = microtime(); // track time
read_hex_file(event.data);
console.log('HEX_PARSER - File parsed in: ' + (microtime() - time_parsing_start).toFixed(4) + ' seconds');
// terminate worker
close();
};

View file

@ -3,9 +3,9 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="author" content="cTn" />
<link type="text/css" rel="stylesheet" href="./css/style.css" media="all" />
<link type="text/css" rel="stylesheet" href="./css/style.css" media="all" />
<script type="text/javascript" src="./js/libraries/google-analytics-bundle.js"></script>
<script type="text/javascript" src="./js/libraries/flotr2.min.js"></script>
<script type="text/javascript" src="./js/libraries/jquery-2.1.0.min.js"></script>
@ -19,7 +19,7 @@
<script type="text/javascript" src="./js/backup_restore.js"></script>
<script type="text/javascript" src="./js/stm32.js"></script>
<!-- Various tabs are divided into separate files (for clarity) -->
<!-- Various tabs are divided into separate files (for clarity) -->
<script type="text/javascript" src="./tabs/default.js"></script>
<script type="text/javascript" src="./tabs/initial_setup.js"></script>
<script type="text/javascript" src="./tabs/pid_tuning.js"></script>
@ -31,7 +31,7 @@
<script type="text/javascript" src="./tabs/sensors.js"></script>
<script type="text/javascript" src="./tabs/cli.js"></script>
<script type="text/javascript" src="./tabs/firmware_flasher.js"></script>
<!-- Various tab styles are divided into separate files (for clarity) -->
<link type="text/css" rel="stylesheet" href="./tabs/default.css" media="all" />
<link type="text/css" rel="stylesheet" href="./tabs/initial_setup.css" media="all" />
@ -82,7 +82,7 @@
<span class="auto_connect">Auto-Connect</span>
</label>
</li>
</ul>
</ul>
</div>
<div id="sensor-status">
<ul>
@ -112,11 +112,11 @@
<li class="tab_cli"><a href="#">CLI</a></li>
</ul>
<div class="clear-both"></div>
</div>
</div>
<div id="content">
</div>
<div id="status-bar">
Port utilization: <span class="port-usage">0%</span> |
Port utilization: <span class="port-usage">0%</span> |
Packet error: <span class="packet-error">0</span> |
Firmware Version: <span class="software-version">0.0</span> |
Cycle Time: <span class="cycle-time">0</span>
@ -124,4 +124,4 @@
</div>
</div>
</body>
</html>
</html>

96
main.js
View file

@ -12,24 +12,24 @@ var service = analytics.getService('ice_cream_app');
var ga_tracker = service.getTracker('UA-32728876-6');
ga_tracker.sendAppView('Application Started');
// Google Analytics stuff end
// Google Analytics stuff end
$(document).ready(function() {
// bind controls
// bind controls
$('#frame .minimize').click(function() {
chrome.app.window.current().minimize();
});
});
$('#frame .maximize').click(function() {
chrome.app.window.current().maximize();
});
$('#frame .close').click(function() {
chrome.app.window.current().close();
});
// alternative - window.navigator.appVersion.match(/Chrome\/([0-9.]*)/)[1];
GUI.log('Running - OS: <strong>' + GUI.operating_system + '</strong>, ' +
GUI.log('Running - OS: <strong>' + GUI.operating_system + '</strong>, ' +
'Chrome: <strong>' + window.navigator.appVersion.replace(/.*Chrome\/([0-9.]*).*/,"$1") + '</strong>, ' +
'Configurator: <strong>' + chrome.runtime.getManifest().version + '</strong>');
@ -47,7 +47,7 @@ $(document).ready(function() {
case 'UNIX':
break;
}
// Tabs
var tabs = $('#tabs > ul');
$('a', tabs).click(function() {
@ -56,19 +56,19 @@ $(document).ready(function() {
GUI.log('You need to connect before you can view any of the tabs', 'red');
return;
}
var self = this;
GUI.tab_switch_cleanup(function() {
// disable previously active tab highlight
$('li', tabs).removeClass('active');
// get tab class name (there should be only one class listed)
var tab = $(self).parent().prop('class');
// Highlight selected tab
$(self).parent().addClass('active');
switch (tab) {
case 'tab_initial_setup':
tab_initialize_initial_setup();
@ -93,27 +93,27 @@ $(document).ready(function() {
break;
case 'tab_sensors':
tab_initialize_sensors();
break;
break;
case 'tab_cli':
tab_initialize_cli();
break;
break;
}
});
}
});
tab_initialize_default();
// listen to all input change events and adjust the value within limits if necessary
$("#content").on('focus', 'input[type="number"]', function() {
var element = $(this);
var val = element.val();
if (!isNaN(val)) {
element.data('previousValue', parseFloat(val));
}
});
$("#content").on('keydown', 'input[type="number"]', function(e) {
// whitelist all that we need for numeric control
if ((e.keyCode >= 96 && e.keyCode <= 105) || (e.keyCode >= 48 && e.keyCode <= 57)) { // allow numpad and standard number keypad
@ -126,40 +126,40 @@ $(document).ready(function() {
e.preventDefault();
}
});
$("#content").on('change', 'input[type="number"]', function() {
var element = $(this);
var min = parseFloat(element.prop('min'));
var max = parseFloat(element.prop('max'));
var step = parseFloat(element.prop('step'));
var val = parseFloat(element.val());
// only adjust minimal end if bound is set
if (element.prop('min')) {
if (val < min) element.val(min);
}
// only adjust maximal end if bound is set
if (element.prop('max')) {
if (val > max) element.val(max);
}
// if entered value is illegal use previous value instead
if (isNaN(val)) {
element.val(element.data('previousValue'));
}
// if step is not set or step is int and value is float use previous value instead
if (isNaN(step) || step % 1 === 0) {
if (val % 1 !== 0) {
element.val(element.data('previousValue'));
}
}
// if step is set and is float and value is int, convert to float, keep decimal places in float according to step *experimental*
if (!isNaN(step) && step % 1 !== 0) {
var decimal_places = String(step).split('.')[1].length;
if (val % 1 === 0) {
element.val(val.toFixed(decimal_places));
} else if (String(val).split('.')[1].length != decimal_places) {
@ -178,10 +178,10 @@ function microtime() {
/*
function add_custom_spinners() {
var spinner_element = '<div class="spinner"><div class="up"></div><div class="down"></div></div>';
$('input[type="number"]').each(function() {
var input = $(this);
// only add new spinner if one doesn't already exist
if (!input.next().hasClass('spinner')) {
var isInt = true;
@ -194,62 +194,62 @@ function add_custom_spinners() {
isInt = false;
}
}
// make space for spinner
input.width(input.width() - 16);
// add spinner
input.after(spinner_element);
// get spinner refference
var spinner = input.next();
// bind UI hooks to spinner
$('.up', spinner).click(function() {
up();
});
$('.up', spinner).mousedown(function() {
$('.up', spinner).mousedown(function() {
GUI.timeout_add('spinner', function() {
GUI.interval_add('spinner', function() {
up();
}, 100, true);
}, 250);
});
$('.up', spinner).mouseup(function() {
GUI.timeout_remove('spinner');
GUI.interval_remove('spinner');
});
$('.up', spinner).mouseleave(function() {
$('.up', spinner).mouseleave(function() {
GUI.timeout_remove('spinner');
GUI.interval_remove('spinner');
});
$('.down', spinner).click(function() {
down();
});
$('.down', spinner).mousedown(function() {
$('.down', spinner).mousedown(function() {
GUI.timeout_add('spinner', function() {
GUI.interval_add('spinner', function() {
down();
}, 100, true);
}, 250);
});
$('.down', spinner).mouseup(function() {
GUI.timeout_remove('spinner');
GUI.interval_remove('spinner');
});
$('.down', spinner).mouseleave(function() {
GUI.timeout_remove('spinner');
GUI.interval_remove('spinner');
});
var up = function() {
if (isInt) {
var current_value = parseInt(input.val());
@ -258,13 +258,13 @@ function add_custom_spinners() {
var current_value = parseFloat(input.val());
var step = parseFloat(input.prop('step'));
var step_decimals = input.prop('step').length - 2;
input.val((current_value + step).toFixed(step_decimals));
}
input.change();
};
var down = function() {
if (isInt) {
var current_value = parseInt(input.val());
@ -273,10 +273,10 @@ function add_custom_spinners() {
var current_value = parseFloat(input.val());
var step = parseFloat(input.prop('step'));
var step_decimals = input.prop('step').length - 2;
input.val((current_value - step).toFixed(step_decimals));
}
input.change();
};
}

View file

@ -2,20 +2,20 @@
"manifest_version": 2,
"minimum_chrome_version": "33",
"version": "0.29",
"author": "cTn",
"name": "Baseflight - Configurator",
"short_name": "baseflight",
"description": "Crossplatform configuration tool for Baseflight flight control system",
"offline_enabled": true,
"app": {
"background": {
"scripts": [ "background.js" ]
}
},
"permissions": [
"https://www.google-analytics.com/",
"https://*.github.com/",
@ -26,7 +26,7 @@
"clipboardWrite",
"notifications"
],
"icons": {
"128": "images/icon_128.png"
}

View file

@ -6,18 +6,18 @@
}
.tab-auxiliary_configuration .heads li {
float: left;
width: 182px;
height: 22px;
line-height: 22px;
text-align: center;
font-weight: bold;
border: 1px solid #8b8b8b;
border-bottom: 0;
border-left: 0;
background-color: #ececec;
}
.tab-auxiliary_configuration .heads li:first-child {
@ -31,12 +31,12 @@
}
.tab-auxiliary_configuration .boxes {
width: 100%;
border-collapse: collapse;
border-collapse: collapse;
}
.tab-auxiliary_configuration .boxes th, .tab-auxiliary_configuration .boxes td {
.tab-auxiliary_configuration .boxes th, .tab-auxiliary_configuration .boxes td {
line-height: 22px;
text-align: center;
border: 1px solid #8b8b8b;
}
.tab-auxiliary_configuration .boxes .name {
@ -53,27 +53,27 @@
}
.tab-auxiliary_configuration .boxes td input {
position: absolute;
margin-top: -6px;
margin-left: -6px;
}
}
.tab-auxiliary_configuration .boxes tr:nth-child(odd) {
background-color: #ececec;
}
}
.tab-auxiliary_configuration .update {
display: block;
float: right;
margin-top: 10px;
height: 28px;
line-height: 28px;
padding: 0 15px 0 15px;
text-align: center;
font-weight: bold;
border: 1px solid silver;
background-color: #ececec;
}

View file

@ -21,7 +21,7 @@
<th>HIGH</th>
<th>LOW</th>
<th>MED</th>
<th>HIGH</th>
<th>HIGH</th>
</tr>
</table>
<a class="update" href="#" title="">Save</a>

View file

@ -13,7 +13,7 @@ function tab_initialize_auxiliary_configuration() {
box_check(AUX_CONFIG_values[i], 0) +
box_check(AUX_CONFIG_values[i], 1) +
box_check(AUX_CONFIG_values[i], 2) +
box_check(AUX_CONFIG_values[i], 3) +
box_check(AUX_CONFIG_values[i], 4) +
box_check(AUX_CONFIG_values[i], 5) +
@ -24,12 +24,12 @@ function tab_initialize_auxiliary_configuration() {
box_check(AUX_CONFIG_values[i], 9) +
box_check(AUX_CONFIG_values[i], 10) +
box_check(AUX_CONFIG_values[i], 11) +
box_check(AUX_CONFIG_values[i], 11) +
'</tr>'
);
}
// UI Hooks
// UI Hooks
$('a.update').click(function() {
// catch the input changes
var main_needle = 0;
@ -40,34 +40,34 @@ function tab_initialize_auxiliary_configuration() {
} else {
AUX_CONFIG_values[main_needle] = bit_clear(AUX_CONFIG_values[main_needle], needle);
}
needle++;
if (needle >= 12) { // 4 aux * 3 checkboxes = 12 bits per line
main_needle++;
needle = 0;
}
});
// send over the data
var AUX_val_buffer_out = new Array();
var needle = 0;
for (var i = 0; i < AUX_CONFIG_values.length; i++) {
AUX_val_buffer_out[needle++] = lowByte(AUX_CONFIG_values[i]);
AUX_val_buffer_out[needle++] = highByte(AUX_CONFIG_values[i]);
}
send_message(MSP_codes.MSP_SET_BOX, AUX_val_buffer_out);
send_message(MSP_codes.MSP_SET_BOX, AUX_val_buffer_out);
// Save changes to EEPROM
send_message(MSP_codes.MSP_EEPROM_WRITE, MSP_codes.MSP_EEPROM_WRITE, false, function() {
GUI.log('EEPROM <span style="color: green">saved</span>');
var element = $('a.update');
element.addClass('success');
GUI.timeout_add('success_highlight', function() {
element.removeClass('success');
}, 2000);
@ -80,16 +80,16 @@ function tab_initialize_auxiliary_configuration() {
send_message(MSP_codes.MSP_RC, MSP_codes.MSP_RC, false, function() {
for (var i = 0; i < AUX_CONFIG.length; i++) {
if (bit_check(CONFIG.mode, i)) {
$('td.name').eq(i).addClass('on').removeClass('off');
$('td.name').eq(i).addClass('on').removeClass('off');
} else {
$('td.name').eq(i).removeClass('on').removeClass('off');
if (AUX_CONFIG_values[i] > 0) {
$('td.name').eq(i).addClass('off');
}
}
}
box_highlight(RC.AUX1, 2);
box_highlight(RC.AUX2, 5);
box_highlight(RC.AUX3, 8);
@ -114,7 +114,7 @@ function box_check(num, pos) {
function box_highlight(val, aux_num) {
var tr = $('table.boxes tr');
var pos = 0; // < 1300
if (val > 1300 && val < 1700) {
pos = 1;
} else if (val > 1700) {

View file

@ -7,48 +7,48 @@
.tab-cli .window {
margin-top: 10px;
height: 350px;
padding: 5px;
overflow-y: scroll;
overflow-x: hidden;
font-family: monospace;
color: white;
border: 1px solid silver;
background-color: black;
-webkit-user-select: text;
}
.tab-cli textarea {
margin-top: 8px;
display: block;
height: 20px;
line-height: 20px;
padding-left: 5px;
border: 1px solid silver;
resize: none;
}
.tab-cli .copy {
display: block;
position: absolute;
bottom: 55px;
right: 40px;
height: 28px;
line-height: 28px;
padding: 0 15px 0 15px;
text-align: center;
font-weight: bold;
border: 1px solid silver;
background-color: #ececec;
}

View file

@ -1,6 +1,6 @@
<div class="tab-cli">
<p>
<span style="color: red;">Note</span>: Leaving CLI tab or pressing Disconnect will <strong>automatically</strong>
<span style="color: red;">Note</span>: Leaving CLI tab or pressing Disconnect will <strong>automatically</strong>
send "<strong>exit</strong>" to the board, which will make the controller save all the changes and <span style="color: red">restart</span>.
</p>
<div class="window">

View file

@ -24,17 +24,17 @@ cli_history = new CliHistory();
function tab_initialize_cli() {
ga_tracker.sendAppView('CLI Page');
GUI.active_tab = 'cli';
// remove any active interval for delayed command
MSP.callbacks_cleanup();
$('#content').load("./tabs/cli.html", function() {
MSP.callbacks_cleanup();
$('#content').load("./tabs/cli.html", function() {
CLI_active = true;
// Enter CLI mode
var bufferOut = new ArrayBuffer(1);
var bufView = new Uint8Array(bufferOut);
bufView[0] = 0x23; // #
serial.send(bufferOut, function(writeInfo) {});
@ -46,11 +46,11 @@ function tab_initialize_cli() {
var out_arr = out_string.split("\n");
cli_history.add(out_string.trim());
var timeout_needle = 0;
for (var i = 0; i < out_arr.length; i++) {
send_slowly(out_arr, i, timeout_needle++);
}
$('.tab-cli textarea').val('');
}
});
@ -64,19 +64,19 @@ function tab_initialize_cli() {
if (event.keyCode in keyDown)
textarea.val(cli_history.next());
});
// apply dynamic width to the textarea element according to cli window width (minus padding and border width)
$('div.tab-cli textarea').width($('div.tab-cli .window').outerWidth() - 7);
// give input element user focus
$('.tab-cli textarea').focus();
$('.tab-cli .copy').click(function() {
var text = $('.tab-cli .window .wrapper').html();
text = text.replace(/<br\s*\/?>/mg,"\n"); // replacing br tags with \n to keep some of the formating
var copyFrom = $('<textarea/>');
copyFrom.text(text);
$('body').append(copyFrom);
copyFrom.select();
@ -88,7 +88,7 @@ function tab_initialize_cli() {
function send_slowly(out_arr, i, timeout_needle) {
GUI.timeout_add('CLI_send_slowly', function() {
var bufferOut = new ArrayBuffer(out_arr[i].length + 1);
var bufferOut = new ArrayBuffer(out_arr[i].length + 1);
var bufView = new Uint8Array(bufferOut);
for (var c_key = 0; c_key < out_arr[i].length; c_key++) {
@ -105,7 +105,7 @@ function send_slowly(out_arr, i, timeout_needle) {
line feed = LF = \n = 0x0A = 10
carriage return = CR = \r = 0x0D = 13
MAC only understands CR
Linux and Unix only understand LF
Windows understands (both) CRLF
@ -117,23 +117,23 @@ var CLI_validate_text = "";
function handle_CLI(readInfo) {
var data = new Uint8Array(readInfo.data);
var text = "";
for (var i = 0; i < data.length; i++) {
if (CLI_valid) {
if (data[i] == 27 || sequence_elements > 0) { // ESC + other
sequence_elements++;
// delete previous space
if (sequence_elements == 1) {
text = text.substring(0, text.length -1);
}
// Reset
if (sequence_elements >= 5) {
sequence_elements = 0;
}
}
if (sequence_elements == 0) {
switch (data[i]) {
case 10: // line feed
@ -154,20 +154,20 @@ function handle_CLI(readInfo) {
// try to catch part of valid CLI enter message
CLI_validate_text += String.fromCharCode(data[i]);
}
char_counter++;
}
if (!CLI_valid && CLI_validate_text.indexOf('CLI') != -1) {
CLI_valid = true;
CLI_validate_text = "";
text = "Entering CLI Mode, type 'exit' to return, or 'help'<br /><br /># ";
}
$('.tab-cli .window .wrapper').append(text);
$('.tab-cli .window').scrollTop($('.tab-cli .window .wrapper').height());
$('.tab-cli .window').scrollTop($('.tab-cli .window .wrapper').height());
// there seems to be some sort of initial rendering glitch in 33+, we will force redraw/refill
$('.tab-cli .window .wrapper').css('webkitTransform', 'scale(1)');
}

View file

@ -1,11 +1,11 @@
.welcome {
float: left;
width: 494px;
height: 171px;
padding: 5px;
border: 1px solid silver;
}
.welcome a {
@ -14,27 +14,27 @@
.changelog {
margin-left: 514px;
margin-bottom: 10px;
border: 1px solid silver;
}
.changelog .title {
line-height: 20px;
text-align: center;
font-weight: bold;
color: white;
border-bottom: 1px solid silver;
background-color: #3f4241;
}
.changelog .wrapper {
height: 150px;
padding: 5px;
overflow-y: scroll;
overflow-x: hidden;
-webkit-user-select: text;
}
.changelog .wrapper span {
@ -45,20 +45,20 @@
}
.donate {
float: left;
width: 504px;
padding: 0 0 5px 0;
border: 1px solid silver;
}
.donate .title {
line-height: 20px;
text-align: center;
font-weight: bold;
color: white;
border-bottom: 1px solid silver;
background-color: #3f4241;
}
@ -67,24 +67,24 @@
}
.donate a {
display: block;
width: 74px;
height: 21px;
margin: auto;
}
.firmware_flasher {
display: block;
float: right;
height: 28px;
line-height: 28px;
padding: 0 15px 0 15px;
text-align: center;
font-weight: bold;
border: 1px solid silver;
background-color: #ececec;
}

View file

@ -21,7 +21,7 @@
This utility is fully <strong>open source</strong> and is available free of charge to all <strong>baseflight</strong> users.<br />
If you found the utility useful, please consider <strong>supporting</strong> its development by donating.<br />
</p>
<a href="http://goo.gl/xQMKN" target="_blank" title="Donate"><img src="./images/btn_donate_SM.gif" alt="Paypal" /></a>
<a href="http://goo.gl/xQMKN" target="_blank" title="Donate"><img src="./images/btn_donate_SM.gif" alt="Paypal" /></a>
</div>
<a class="firmware_flasher" href="#">Firmware Flasher</a>
<a class="firmware_flasher" href="#">Firmware Flasher</a>
</div>

View file

@ -1,10 +1,10 @@
function tab_initialize_default() {
GUI.active_tab = 'default';
$('#content').load("./tabs/default.html", function() {
$('#content').load("./tabs/default.html", function() {
// load changelog content
$('div.changelog.configurator .wrapper').load('./changelog.html');
// UI Hooks
$('a.firmware_flasher').click(function() {
tab_initialize_firmware_flasher();

View file

@ -6,7 +6,7 @@
}
.tab-firmware_flasher .info .progress {
width: 140px;
border: 1px solid silver;
}
.tab-firmware_flasher .info .progress::-webkit-progress-value {
@ -20,10 +20,10 @@
}
.tab-firmware_flasher .note {
float: left;
margin-bottom: 10px;
padding: 5px;
border: 1px dotted silver;
}
.tab-firmware_flasher .note p {
@ -42,15 +42,15 @@
a.load_file, a.load_remote_file {
display: block;
float: left;
margin: 0 10px 0 0;
padding: 0 10px 0 10px;
height: 20px;
line-height: 20px;
text-align: center;
font-weight: bold;
border: 1px solid silver;
background-color: #ececec;
}
@ -60,14 +60,14 @@ a.load_file:hover, a.load_remote_file:hover {
a.flash_firmware {
display: block;
float: left;
padding: 0 10px 0 10px;
height: 20px;
line-height: 20px;
text-align: center;
font-weight: bold;
border: 1px solid silver;
background-color: #ececec;
}
@ -84,35 +84,35 @@ a.flash_firmware:hover {
a.back {
display: block;
position: absolute;
bottom: 10px;
height: 28px;
line-height: 28px;
padding: 0 15px 0 15px;
text-align: center;
font-weight: bold;
border: 1px solid silver;
background-color: #ececec;
}
a.back:hover {
background-color: #dedcdc;
}
.warning {
.warning {
width: 620px;
border: 1px solid silver;
}
.warning .title {
line-height: 20px;
text-align: center;
font-weight: bold;
color: white;
border-bottom: 1px solid silver;
background-color: #cd4c4c;
}
@ -121,20 +121,20 @@ a.back:hover {
}
.tab-firmware_flasher .git_info {
display: none;
width: 620px;
margin-bottom: 10px;
border: 1px solid silver;
}
.tab-firmware_flasher .git_info .title {
line-height: 20px;
text-align: center;
font-weight: bold;
color: white;
border-bottom: 1px solid silver;
background-color: #3f4241;
}

View file

@ -4,7 +4,7 @@
<strong>Size:</strong><span class="size">0 bytes</span><br />
<strong>Status:</strong><span class="status">Firmware not loaded</span><br />
<strong>Progress:</strong><progress class="progress" value="0" min="0" max="100"></progress>
</div>
</div>
<div class="note">
<p>
If you are flashing board with <strong>baseflight</strong> already flashed (updating), leave this checkbox unchecked.<br />
@ -27,7 +27,7 @@
<strong>Date:</strong> <span class="date"></span><br />
<strong>Message:</strong> <span class="message"></span>
</p>
</div>
</div>
<div class="warning">
<div class="title">Warning</div>
<p>

View file

@ -1,10 +1,10 @@
function tab_initialize_firmware_flasher() {
ga_tracker.sendAppView('Firmware Flasher');
GUI.active_tab = 'firmware_flasher';
var intel_hex = false; // standard intel hex in string format
var parsed_hex = false; // parsed raw hex in array format
$('#content').load("./tabs/firmware_flasher.html", function() {
// UI Hooks
$('a.load_file').click(function() {
@ -14,14 +14,14 @@ function tab_initialize_firmware_flasher() {
console.log('No valid file selected, aborting');
return;
}
// hide github info (if it exists)
$('div.git_info').slideUp();
chrome.fileSystem.getDisplayPath(fileEntry, function(path) {
console.log('Loading file from: ' + path);
$('span.path').html(path);
fileEntry.file(function(file) {
var reader = new FileReader();
@ -32,20 +32,20 @@ function tab_initialize_firmware_flasher() {
reader.abort();
}
};
reader.onloadend = function(e) {
if (e.total != 0 && e.total == e.loaded) {
console.log('File loaded');
intel_hex = e.target.result;
parse_hex(intel_hex, function(data) {
parsed_hex = data;
if (parsed_hex) {
STM32.GUI_status('<span style="color: green">Firmware loaded, ready for flashing</span>');
$('a.flash_firmware').removeClass('locked');
$('span.size').html(parsed_hex.bytes_total + ' bytes');
} else {
STM32.GUI_status('<span style="color: red">HEX file appears to be corrupted</span>');
@ -59,18 +59,18 @@ function tab_initialize_firmware_flasher() {
});
});
});
$('a.load_remote_file').click(function() {
$('a.load_remote_file').click(function() {
$.get('https://raw.github.com/multiwii/baseflight/master/obj/baseflight.hex', function(data) {
intel_hex = data;
parse_hex(intel_hex, function(data) {
parsed_hex = data;
if (parsed_hex) {
STM32.GUI_status('<span style="color: green">Remote Firmware loaded, ready for flashing</span>');
$('a.flash_firmware').removeClass('locked');
$('span.path').html('Using remote Firmware');
$('span.size').html(parsed_hex.bytes_total + ' bytes');
} else {
@ -81,25 +81,25 @@ function tab_initialize_firmware_flasher() {
STM32.GUI_status('<span style="color: red">Failed to load remote firmware</span>');
$('a.flash_firmware').addClass('locked');
});
$.get('https://api.github.com/repos/multiwii/baseflight/commits?page=1&per_page=1&path=obj/baseflight.hex', function(data) {
var data = data[0];
var d = new Date(data.commit.author.date);
var date = ('0' + (d.getMonth() + 1)).slice(-2) + '.' + ('0' + (d.getDate() + 1)).slice(-2) + '.' + d.getFullYear();
date += ' @ ' + ('0' + d.getHours()).slice(-2) + ':' + ('0' + d.getMinutes()).slice(-2);
$('div.git_info .committer').html(data.commit.author.name);
$('div.git_info .date').html(date);
$('div.git_info .message').html(data.commit.message);
$('div.git_info').slideDown();
});
});
$('a.flash_firmware').click(function() {
if (!$(this).hasClass('locked')) {
if (!GUI.connect_lock) { // button disabled while flashing is in progress
if (parsed_hex != false) {
if (parsed_hex != false) {
STM32.connect(parsed_hex);
} else {
STM32.GUI_status('<span style="color: red">Firmware not loaded</span>');
@ -107,12 +107,12 @@ function tab_initialize_firmware_flasher() {
}
}
});
chrome.storage.local.get('no_reboot_sequence', function(result) {
if (typeof result.no_reboot_sequence === 'undefined') {
// wasn't saved yet, save and push false to the GUI
chrome.storage.local.set({'no_reboot_sequence': false});
$('input.updating').prop('checked', false);
} else {
if (result.no_reboot_sequence) {
@ -122,27 +122,27 @@ function tab_initialize_firmware_flasher() {
$('input.updating').prop('checked', false);
}
}
// bind UI hook so the status is saved on change
$('input.updating').change(function() {
var status = $(this).is(':checked');
if (status) {
$('label.flash_on_connect_wrapper').show();
} else {
$('label.flash_on_connect_wrapper').hide();
$('input.flash_on_connect').prop('checked', false).change();
}
chrome.storage.local.set({'no_reboot_sequence': status}, function() {});
});
});
chrome.storage.local.get('flash_on_connect', function(result) {
if (typeof result.flash_on_connect === 'undefined') {
// wasn't saved yet, save and push false to the GUI
chrome.storage.local.set({'flash_on_connect': false});
$('input.flash_on_connect').prop('checked', false);
} else {
if (result.flash_on_connect) {
@ -151,27 +151,27 @@ function tab_initialize_firmware_flasher() {
$('input.flash_on_connect').prop('checked', false);
}
}
$('input.flash_on_connect').change(function() {
var status = $(this).is(':checked');
if (status) {
var flashing_port;
var start = function() {
PortHandler.port_detected('flash_next_device', function(result) {
flashing_port = result[0];
GUI.log('Detected: <strong>' + flashing_port + '</strong> - triggering flash on connect');
console.log('Detected: ' + flashing_port + ' - triggering flash on connect');
// Trigger regular Flashing sequence
$('a.flash_firmware').click();
// Detect port removal to create a new callback
end();
}, false, true);
};
var end = function() {
PortHandler.port_removed('flashed_device_removed', function(result) {
for (var i = 0; i < result.length; i++) {
@ -179,28 +179,28 @@ function tab_initialize_firmware_flasher() {
// flashed device removed
GUI.log('Removed: <strong>' + flashing_port + '</strong> - ready for next device');
console.log('Removed: ' + flashing_port + ' - ready for next device');
flashing_port = false;
start();
return;
}
}
// different device removed, we need to retry
end();
}, false, true);
};
start();
} else {
PortHandler.flush_callbacks();
}
chrome.storage.local.set({'flash_on_connect': status}, function() {});
}).change();
});
$('a.back').click(function() {
if (!GUI.connect_lock) { // button disabled while flashing is in progress
GUI.tab_switch_cleanup(function() {
@ -216,12 +216,12 @@ function tab_initialize_firmware_flasher() {
function parse_hex(str, callback) {
// parsing hex in different thread
var worker = new Worker('./js/workers/hex_parser.js');
// "callback"
worker.onmessage = function (event) {
callback(event.data);
};
// send data/string over for processing
worker.postMessage(str);
}

View file

@ -3,10 +3,10 @@
.tab-gps .GPS_info {
float: left;
display: block;
width: 170px;
border: 1px solid silver;
}
.tab-gps .GPS_info table {
@ -15,11 +15,11 @@
}
.tab-gps .GPS_signal_strength {
float: left;
margin-left: 10px;
width: 200px;
border: 1px solid silver;
}
.tab-gps .GPS_signal_strength table {
@ -29,11 +29,11 @@
.tab-gps .GPS_info .head,
.tab-gps .GPS_signal_strength .head {
display: block;
text-align: center;
line-height: 20px;
font-weight: bold;
border-bottom: 1px solid silver;
background-color: #ececec;
}

View file

@ -25,7 +25,7 @@
<tr>
<td>Dist to Home:</td>
<td class="distToHome">0</td>
</tr>
</tr>
</table>
</div>
<div class="GPS_signal_strength">
@ -110,12 +110,12 @@
<td>0</td>
<td>0</td>
<td><progress value="0" max="16"></progress></td>
</tr>
</tr>
<tr>
<td>0</td>
<td>0</td>
<td><progress value="0" max="16"></progress></td>
</tr>
</tr>
</table>
</div>
</div>
</div>
</div>

View file

@ -1,7 +1,7 @@
function tab_initialize_gps () {
ga_tracker.sendAppView('GPS Page');
GUI.active_tab = 'gps';
send_message(MSP_codes.MSP_RAW_GPS, MSP_codes.MSP_RAW_GPS, false, function() {
$('#content').load("./tabs/gps.html", function() {
// enable data pulling
@ -13,10 +13,10 @@ function tab_initialize_gps () {
$('.GPS_info td.speed').html(GPS_DATA.speed + ' cm/s');
$('.GPS_info td.sats').html(GPS_DATA.numSat);
$('.GPS_info td.distToHome').html(GPS_DATA.distanceToHome + ' m');
// Update GPS Signal Strengths
var e_ss_table = $('div.GPS_signal_strength table tr:not(.titles)');
for (var i = 0; i < GPS_DATA.chn.length; i++) {
var row = e_ss_table.eq(i);
@ -24,7 +24,7 @@ function tab_initialize_gps () {
$('td', row).eq(1).html(GPS_DATA.quality[i]);
$('td', row).eq(2).find('progress').val(GPS_DATA.cno[i]);
}
send_message(MSP_codes.MSP_STATUS, MSP_codes.MSP_STATUS);
send_message(MSP_codes.MSP_RAW_GPS, MSP_codes.MSP_RAW_GPS);
send_message(MSP_codes.MSP_GPSSVINFO, MSP_codes.MSP_GPSSVINFO);

View file

@ -6,16 +6,16 @@
}
.tab-initial_setup .section a {
display: block;
float: left;
width: 170px;
height: 24px;
line-height: 24px;
text-align: center;
font-weight: bold;
border: 1px solid silver;
background-color: #ececec;
}
@ -38,61 +38,61 @@
}
.tab-initial_setup .section p {
margin-left: 180px;
padding: 5px;
border: 1px dotted silver;
}
#interactive_block {
float: left;
height: 280px;
width: 400px;
border: 1px solid silver;
background-color: white;
}
#interactive_block .model {
display: block;
margin: 10px 0 0 10px;
font-weight: bold;
}
#interactive_block a.reset {
position: absolute;
display: block;
margin-left: 10px;
margin-top: 215px;
height: 28px;
line-height: 28px;
padding: 0 15px 0 15px;
text-align: center;
font-weight: bold;
border: 1px solid silver;
background-color: #ececec;
z-index: 100;
}
}
#interactive_block a.reset:hover {
background-color: #dedcdc;
}
#perspective {
-webkit-perspective: 800;
-webkit-perspective-origin: 50% 150px; /* 150px = (350px / 2) - 25px */
}
}
#cube {
position: relative;
top: 110px;
left: 150px; /* (916px / 2) - 50px */
height: 100px;
width: 100px;
-webkit-transform-style: preserve-3d;
}
#cubePITCH {
@ -103,7 +103,7 @@
}
#cube .face {
position: absolute;
color: white;
font-size: 25px;
text-align: center;
@ -114,7 +114,7 @@
line-height: 200px;
font-size: 20px;
-webkit-transform: rotateX(-90deg) translateZ(-50px);
background-color: purple;
}
@ -122,7 +122,7 @@
width: 100px;
height: 50px;
line-height: 50px;
-webkit-transform: translateZ(100px);
background-color: blue;
}
@ -130,7 +130,7 @@
width: 200px;
height: 50px;
line-height: 50px;
-webkit-transform: rotateY(90deg);
background-color: green;
}
@ -138,7 +138,7 @@
width: 100px;
height: 50px;
line-height: 50px;
-webkit-transform: rotateY(180deg) translateZ(100px);
background-color: black;
}
@ -146,7 +146,7 @@
width: 200px;
height: 50px;
line-height: 50px;
-webkit-transform: rotateY(-90deg) translateZ(100px);
background-color: red;
}
@ -154,19 +154,19 @@
width: 100px;
height: 200px;
line-height: 200px;
-webkit-transform: rotateX(90deg) translateZ(100px);
background-color: silver;
}
}
.tab-initial_setup .battery,
.tab-initial_setup .throttle,
.tab-initial_setup .acc-trim,
.tab-initial_setup .magnetometer {
float: left;
display: block;
margin-left: 10px;
border: 1px solid silver;
}
.tab-initial_setup .magnetometer {
@ -177,11 +177,11 @@
.tab-initial_setup .acc-trim .head,
.tab-initial_setup .magnetometer .head {
display: block;
text-align: center;
line-height: 20px;
font-weight: bold;
border-bottom: 1px solid silver;
background-color: #ececec;
}
@ -203,24 +203,24 @@
float: left;
width: 100px;
height: 22px;
margin-bottom: 2px;
line-height: 22px;
}
.tab-initial_setup .battery dd {
height: 22px;
margin-left: 100px;
margin-bottom: 2px;
line-height: 22px;
}
.tab-initial_setup .battery input {
width: 70px;
height: 20px;
line-height: 20px;
border: 1px solid silver;
text-align: center;
}
@ -228,24 +228,24 @@
float: left;
width: 85px;
height: 22px;
margin-bottom: 2px;
line-height: 22px;
}
.tab-initial_setup .throttle dd {
height: 22px;
margin-left: 85px;
margin-bottom: 2px;
line-height: 22px;
}
.tab-initial_setup .throttle input {
width: 70px;
height: 20px;
line-height: 20px;
border: 1px solid silver;
text-align: center;
}
@ -254,12 +254,12 @@
width: 40px;
height: 22px;
line-height: 22px;
margin-bottom: 2px;
}
.tab-initial_setup .acc-trim dd {
height: 22px;
margin-left: 40px;
margin-bottom: 2px;
}
@ -267,7 +267,7 @@
width: 70px;
height: 20px;
line-height: 20px;
border: 1px solid silver;
text-align: center;
}
@ -276,13 +276,13 @@
width: 100px;
height: 20px;
line-height: 22px;
margin-bottom: 2px;
}
.tab-initial_setup .magnetometer dd {
height: 20px;
line-height: 22px;
margin-left: 100px;
margin-bottom: 2px;
}
@ -290,23 +290,23 @@
width: 70px;
height: 20px;
line-height: 20px;
border: 1px solid silver;
text-align: center;
}
.tab-initial_setup .update {
display: block;
float: left;
margin: 10px 0 0 10px;
width: 80px;
height: 20px;
line-height: 20px;
text-align: center;
font-weight: bold;
border: 1px solid silver;
background-color: #ececec;
}
@ -319,19 +319,19 @@
.tab-initial_setup .compass-wrapper {
display: none;
position: absolute;
bottom: 10px;
right: 10px;
border: 1px solid silver;
border-radius: 50%;
}
}
.tab-initial_setup #compass {
position: relative;
width: 150px;
height: 150px;
border: 6px dashed silver;
border-radius: 50%;
}
@ -340,68 +340,68 @@
font-weight: bold;
}
.tab-initial_setup #compass span:nth-child(1) {
left: 70px;
left: 70px;
top: 5px;
}
}
.tab-initial_setup #compass span:nth-child(2) {
right: 5px;
right: 5px;
top: 70px;
}
}
.tab-initial_setup #compass span:nth-child(3) {
left: 70px;
left: 70px;
bottom: 5px;
}
}
.tab-initial_setup #compass span:nth-child(4) {
left: 5px;
left: 5px;
top: 70px;
}
}
.tab-initial_setup #compass .pointer {
position: absolute;
height: 150px;
width: 150px;
-webkit-transform: rotate(0deg);
-webkit-transform: rotate(0deg);
}
.tab-initial_setup #compass .pointer .tip {
position: absolute;
margin-top: 14px;
margin-left: -6px;
width: 0;
height: 0;
width: 0;
height: 0;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-bottom: 30px solid red;
}
.tab-initial_setup #compass .pointer .stick {
position: absolute;
display: block;
margin-top: -22px;
margin-right: 69px;
width: 4px;
height: 30px;
background-color: black;
}
.tab-initial_setup #compass .value {
position: relative;
top: 75px;
left: 53px;
width: 40px;
height: 16px;
height: 16px;
line-height: 16px;
text-align: center;
background-color: #f2f2f2;
border: 1px solid silver;
}

View file

@ -1,28 +1,28 @@
function tab_initialize_initial_setup() {
ga_tracker.sendAppView('Initial Setup');
GUI.active_tab = 'initial_setup';
send_message(MSP_codes.MSP_ACC_TRIM, MSP_codes.MSP_ACC_TRIM, false, function() {
send_message(MSP_codes.MSP_MISC, MSP_codes.MSP_MISC, false, function() {
$('#content').load("./tabs/initial_setup.html", function() {
var yaw_fix = 0.0;
// Fill in misc stuff
$('input[name="mincellvoltage"]').val(MISC.vbatmincellvoltage);
$('input[name="maxcellvoltage"]').val(MISC.vbatmaxcellvoltage);
$('input[name="voltagescale"]').val(MISC.vbatscale);
$('input[name="minthrottle"]').val(MISC.minthrottle);
$('input[name="maxthrottle"]').val(MISC.maxthrottle);
$('input[name="failsafe_throttle"]').val(MISC.failsafe_throttle);
$('input[name="mincommand"]').val(MISC.mincommand);
$('input[name="mag_declination"]').val(MISC.mag_declination / 10);
// Fill in the accel trimms from CONFIG object
$('input[name="pitch"]').val(CONFIG.accelerometerTrims[0]);
$('input[name="roll"]').val(CONFIG.accelerometerTrims[1]);
// Display multiType
var str = '';
switch (CONFIG.multiType) {
@ -64,13 +64,13 @@ function tab_initialize_initial_setup() {
case 14: // AIRPLANE
str = 'Airplane';
break;
case 15: // Heli 120
case 15: // Heli 120
str = 'Heli 120';
break;
case 16: // Heli 90
case 16: // Heli 90
str = 'Heli 90';
break;
case 17: // Vtail
case 17: // Vtail
str = 'Vtail';
break;
case 18: // HEX6 H
@ -86,43 +86,43 @@ function tab_initialize_initial_setup() {
str = 'Singlecopter';
break;
}
$('span.model').html('Model: ' + str);
// UI Hooks
$('a.calibrateAccel').click(function() {
var self = $(this);
if (!self.hasClass('calibrating')) {
self.addClass('calibrating');
// During this period MCU won't be able to process any serial commands because its locked in a for/while loop
// until this operation finishes, sending more commands through data_poll() will result in serial buffer overflow
GUI.interval_pause('initial_setup_data_pull');
send_message(MSP_codes.MSP_ACC_CALIBRATION, MSP_codes.MSP_ACC_CALIBRATION, false, function() {
GUI.log('Accelerometer calibration started');
});
GUI.timeout_add('button_reset', function() {
GUI.interval_resume('initial_setup_data_pull');
GUI.log('Accelerometer calibration finished');
self.removeClass('calibrating');
}, 2000);
}
});
$('a.calibrateMag').click(function() {
var self = $(this);
if (!self.hasClass('calibrating')) {
self.addClass('calibrating');
send_message(MSP_codes.MSP_MAG_CALIBRATION, MSP_codes.MSP_MAG_CALIBRATION, false, function() {
GUI.log('Magnetometer calibration started');
});
GUI.timeout_add('button_reset', function() {
GUI.log('Magnetometer calibration finished');
self.removeClass('calibrating');
@ -133,38 +133,38 @@ function tab_initialize_initial_setup() {
$('a.resetSettings').click(function() {
send_message(MSP_codes.MSP_RESET_CONF, MSP_codes.MSP_RESET_CONF, false, function() {
GUI.log('Settings restored to <strong>default</strong>');
GUI.tab_switch_cleanup(function() {
tab_initialize_initial_setup();
});
});
});
$('a.update').click(function() {
CONFIG.accelerometerTrims[0] = parseInt($('input[name="pitch"]').val());
CONFIG.accelerometerTrims[1] = parseInt($('input[name="roll"]').val());
var buffer_out = new Array();
buffer_out[0] = lowByte(CONFIG.accelerometerTrims[0]);
buffer_out[1] = highByte(CONFIG.accelerometerTrims[0]);
buffer_out[2] = lowByte(CONFIG.accelerometerTrims[1]);
buffer_out[3] = highByte(CONFIG.accelerometerTrims[1]);
buffer_out[3] = highByte(CONFIG.accelerometerTrims[1]);
// Send over the new trims
send_message(MSP_codes.MSP_SET_ACC_TRIM, buffer_out);
MISC.vbatmincellvoltage = parseFloat($('input[name="mincellvoltage"]').val()) * 10;
MISC.vbatmaxcellvoltage = parseFloat($('input[name="maxcellvoltage"]').val()) * 10;
MISC.vbatscale = parseInt($('input[name="voltagescale"]').val());
MISC.minthrottle = parseInt($('input[name="minthrottle"]').val());
MISC.maxthrottle = parseInt($('input[name="maxthrottle"]').val());
MISC.failsafe_throttle = parseInt($('input[name="failsafe_throttle"]').val());
MISC.mincommand = parseInt($('input[name="mincommand"]').val());
MISC.mag_declination = parseFloat($('input[name="mag_declination"]').val()) * 10;
// we also have to fill the unsupported bytes
var buffer_out = new Array();
buffer_out[0] = 0; // powerfailmeter
@ -189,56 +189,56 @@ function tab_initialize_initial_setup() {
buffer_out[19] = MISC.vbatmincellvoltage;
buffer_out[20] = MISC.vbatmaxcellvoltage;
buffer_out[21] = 0; // vbatlevel_crit (unused)
// Send over new misc
send_message(MSP_codes.MSP_SET_MISC, buffer_out);
// Save changes to EEPROM
send_message(MSP_codes.MSP_EEPROM_WRITE, MSP_codes.MSP_EEPROM_WRITE, false, function() {
GUI.log('EEPROM <span style="color: green">saved</span>');
var element = $('a.update');
element.addClass('success');
GUI.timeout_add('success_highlight', function() {
element.removeClass('success');
}, 2000);
});
});
});
// reset yaw button hook
$('div#interactive_block > a.reset').click(function() {
yaw_fix = SENSOR_DATA.kinematicsZ * - 1.0;
console.log("YAW reset to 0");
});
});
$('#content .backup').click(configuration_backup);
$('#content .restore').click(configuration_restore);
GUI.interval_add('initial_setup_data_pull', function() {
GUI.interval_add('initial_setup_data_pull', function() {
// Update voltage indicator
$('.bat-voltage').html(ANALOG.voltage + ' V');
// Request new data, if transmission fails it doesn't matter as new transmission will be requested after 50ms
send_message(MSP_codes.MSP_STATUS, MSP_codes.MSP_STATUS, false, function() { // cycle time, active sensors, etc...
send_message(MSP_codes.MSP_ANALOG, MSP_codes.MSP_ANALOG, false, function() { // battery voltage
send_message(MSP_codes.MSP_ATTITUDE, MSP_codes.MSP_ATTITUDE, false, function() { // kinematics
// Update cube
var cube = $('div#cube');
cube.css('-webkit-transform', 'rotateY(' + ((SENSOR_DATA.kinematicsZ * -1.0) - yaw_fix) + 'deg)');
$('#cubePITCH', cube).css('-webkit-transform', 'rotateX(' + SENSOR_DATA.kinematicsY + 'deg)');
$('#cubeROLL', cube).css('-webkit-transform', 'rotateZ(' + SENSOR_DATA.kinematicsX + 'deg)');
$('#cubeROLL', cube).css('-webkit-transform', 'rotateZ(' + SENSOR_DATA.kinematicsX + 'deg)');
/*
// Update Compass
$('div#compass .pointer').css('-webkit-transform', 'rotate(' + (SENSOR_DATA.kinematicsZ) + 'deg)');
$('div#compass .pointer').css('-webkit-transform', 'rotate(' + (SENSOR_DATA.kinematicsZ) + 'deg)');
$('div#compass .value').html(SENSOR_DATA.kinematicsZ + '&deg;');
*/
});
});
});
});
}, 50, true);
});
});

View file

@ -1,5 +1,5 @@
.tab-motor_outputs {
}
}
.tab-motor_outputs .right.servos {
margin-right: -10px;
}
@ -10,7 +10,7 @@
float: left;
width: 42px;
margin-right: 10px;
text-align: center;
}
.tab-motor_outputs .titles .active {
@ -18,24 +18,24 @@
}
.tab-motor_outputs .m-block {
float: left;
width: 40px;
height: 160px;
margin-right: 10px;
border: 1px solid silver;
background-color: #e9e9e9;
}
.tab-motor_outputs .indicator {
position: absolute;
width: 40px;
}
.tab-motor_outputs p {
margin-top: 20px;
padding: 5px;
border: 1px dotted silver;
}
.tab-motor_outputs .motor_testing {
@ -46,7 +46,7 @@
}
.tab-motor_outputs .motor_testing .sliders input {
-webkit-appearance: slider-vertical;
width: 48px;
}
.tab-motor_outputs .motor_testing .values {
@ -54,23 +54,23 @@
}
.tab-motor_outputs .motor_testing .values li {
float: left;
width: 51px;
text-align: center;
}
.tab-motor_outputs .motor_testing .notice {
float: right;
width: 420px;
margin-top: 20px;
padding: 5px;
border: 1px dotted silver;
}
.tab-motor_outputs .motor_testing .notice input[type="checkbox"] {
margin-left: 5px;
vertical-align: middle;
}

View file

@ -46,7 +46,7 @@
<div class="clear-both"></div>
<p>
Bars on the <strong>left</strong> are representing raw PWM signal for <strong>ESCs</strong>.<br />
Bars on the <strong>right</strong> are representing raw PWM signal for <strong>Servos</strong>.<br />
Bars on the <strong>right</strong> are representing raw PWM signal for <strong>Servos</strong>.<br />
</p>
<div class="motor_testing">
<div class="left">

View file

@ -1,7 +1,7 @@
function tab_initialize_motor_outputs() {
ga_tracker.sendAppView('Motor Outputs Page');
GUI.active_tab = 'motor_outputs';
send_message(MSP_codes.MSP_MISC, MSP_codes.MSP_MISC, false, function() {
send_message(MSP_codes.MSP_MOTOR, MSP_codes.MSP_MOTOR, false, function() {
$('#content').load("./tabs/motor_outputs.html", function() {
@ -9,64 +9,64 @@ function tab_initialize_motor_outputs() {
if (bit_check(CONFIG.capability, 2)) {
$('div.motor_testing').show();
}
var number_of_valid_outputs = (MOTOR_DATA.indexOf(0) > -1) ? MOTOR_DATA.indexOf(0) : 8;
$('input.min').val(MISC.mincommand);
$('input.max').val(MISC.maxthrottle);
$('div.sliders input').prop('min', MISC.mincommand);
$('div.sliders input').prop('max', MISC.maxthrottle);
$('div.sliders input').val(MISC.mincommand);
$('div.values li:not(:last)').html(MISC.mincommand);
// UI hooks
$('div.sliders input:not(.master)').change(function() {
var index = $(this).index();
$('div.values li').eq(index).html($(this).val());
// send data to mcu
var buffer_out = [];
for (var i = 0; i < 8; i++) {
var val = parseInt($('div.sliders input').eq(i).val());
buffer_out.push(lowByte(val));
buffer_out.push(highByte(val));
}
send_message(MSP_codes.MSP_SET_MOTOR, buffer_out);
});
$('div.sliders input.master').change(function() {
var val = $(this).val();
$('div.sliders input:not(:disabled, :last)').val(val);
$('div.values li:not(:last)').slice(0, number_of_valid_outputs).html(val);
$('div.sliders input:not(:last):first').change();
});
$('div.notice input[type="checkbox"]').change(function() {
if ($(this).is(':checked')) {
$('div.sliders input').slice(0, number_of_valid_outputs).prop('disabled', false);
// unlock master slider
$('div.sliders input:last').prop('disabled', false);
} else {
// disable sliders / min max
$('div.sliders input').prop('disabled', true);
// change all values to default
$('div.sliders input').val(1000);
$('div.values li:not(:last)').html(1000);
// trigger change event so values are sent to mcu
$('div.sliders input').change();
}
});
// enable Motor data pulling
GUI.interval_add('motor_poll', function() {
// Request New data
@ -74,26 +74,26 @@ function tab_initialize_motor_outputs() {
send_message(MSP_codes.MSP_MOTOR, MSP_codes.MSP_MOTOR, false, function() {
send_message(MSP_codes.MSP_SERVO, MSP_codes.MSP_SERVO, false, function() {
// Update UI
var block_height = $('div.m-block:first').height();
for (var i = 0; i < MOTOR_DATA.length; i++) {
var data = MOTOR_DATA[i] - 1000;
var margin_top = block_height - (data * (block_height / 1000));
var height = (data * (block_height / 1000));
var color = parseInt(data * 0.256);
$('.motor-' + i + ' .indicator').css({'margin-top' : margin_top + 'px', 'height' : height + 'px', 'background-color' : 'rgb(' + color + ',0,0)'});
}
for (var i = 0; i < SERVO_DATA.length; i++) {
var data = SERVO_DATA[i] - 1000;
var margin_top = block_height - (data * (block_height / 1000));
var height = (data * (block_height / 1000));
var color = parseInt(data * 0.256);
$('.servo-' + i + ' .indicator').css({'margin-top' : margin_top + 'px', 'height' : height + 'px', 'background-color' : 'rgb(' + color + ',0,0)'});
}
}
});
});
});

View file

@ -5,11 +5,11 @@
}
.tab-pid_tuning table {
float: left;
border-collapse: collapse;
}
.tab-pid_tuning table,
.tab-pid_tuning table th,
.tab-pid_tuning table,
.tab-pid_tuning table th,
.tab-pid_tuning table td {
padding: 4px;
border: 1px solid #8b8b8b;
@ -35,32 +35,32 @@
width: 96px;
height: 20px;
line-height: 20px;
padding: 0 5px 0 5px;
text-align: right;
}
.tab-pid_tuning .profile {
float: left;
margin-top: 10px;
width: 70px;
border: 1px solid silver;
}
.tab-pid_tuning .profile .head {
display: block;
text-align: center;
line-height: 20px;
font-weight: bold;
border-bottom: 1px solid silver;
background-color: #ececec;
}
.tab-pid_tuning .profile input {
padding-left: 30px;
width: 40px;
height: 20px;
line-height: 20px;
@ -78,23 +78,23 @@
.tab-pid_tuning .refresh {
display: block;
float: right;
margin-top: 10px;
height: 28px;
line-height: 28px;
padding: 0 15px 0 15px;
text-align: center;
font-weight: bold;
border: 1px solid silver;
background-color: #ececec;
}
.tab-pid_tuning .refresh {
margin-right: 10px;
}
}
.tab-pid_tuning .update:hover,
.tab-pid_tuning .refresh:hover {
background-color: #dedcdc;

View file

@ -1,7 +1,7 @@
function tab_initialize_pid_tuning() {
ga_tracker.sendAppView('PID Tuning');
GUI.active_tab = 'pid_tuning';
send_message(MSP_codes.MSP_PID, MSP_codes.MSP_PID, false, function() {
send_message(MSP_codes.MSP_RC_TUNING, MSP_codes.MSP_RC_TUNING, false, function() {
$('#content').load("./tabs/pid_tuning.html", function() {
@ -10,220 +10,220 @@ function tab_initialize_pid_tuning() {
$('.pid_tuning .ROLL input').each(function() {
switch (i) {
case 0:
$(this).val(PIDs[0][i++].toFixed(1));
$(this).val(PIDs[0][i++].toFixed(1));
break;
case 1:
$(this).val(PIDs[0][i++].toFixed(3));
$(this).val(PIDs[0][i++].toFixed(3));
break;
case 2:
$(this).val(PIDs[0][i++].toFixed(0));
$(this).val(PIDs[0][i++].toFixed(0));
break;
}
}
});
i = 0;
$('.pid_tuning .PITCH input').each(function() {
switch (i) {
case 0:
$(this).val(PIDs[1][i++].toFixed(1));
$(this).val(PIDs[1][i++].toFixed(1));
break;
case 1:
$(this).val(PIDs[1][i++].toFixed(3));
$(this).val(PIDs[1][i++].toFixed(3));
break;
case 2:
$(this).val(PIDs[1][i++].toFixed(0));
$(this).val(PIDs[1][i++].toFixed(0));
break;
}
}
});
i = 0;
$('.pid_tuning .YAW input').each(function() {
switch (i) {
case 0:
$(this).val(PIDs[2][i++].toFixed(1));
$(this).val(PIDs[2][i++].toFixed(1));
break;
case 1:
$(this).val(PIDs[2][i++].toFixed(3));
$(this).val(PIDs[2][i++].toFixed(3));
break;
case 2:
$(this).val(PIDs[2][i++].toFixed(0));
$(this).val(PIDs[2][i++].toFixed(0));
break;
}
}
});
i = 0;
$('.pid_tuning .ALT input').each(function() {
switch (i) {
case 0:
$(this).val(PIDs[3][i++].toFixed(1));
$(this).val(PIDs[3][i++].toFixed(1));
break;
case 1:
$(this).val(PIDs[3][i++].toFixed(3));
$(this).val(PIDs[3][i++].toFixed(3));
break;
case 2:
$(this).val(PIDs[3][i++].toFixed(0));
$(this).val(PIDs[3][i++].toFixed(0));
break;
}
}
});
i = 0;
$('.pid_tuning .Pos input').each(function() {
$(this).val(PIDs[4][i++].toFixed(2));
$(this).val(PIDs[4][i++].toFixed(2));
});
i = 0;
$('.pid_tuning .PosR input').each(function() {
switch (i) {
case 0:
$(this).val(PIDs[5][i++].toFixed(1));
$(this).val(PIDs[5][i++].toFixed(1));
break;
case 1:
$(this).val(PIDs[5][i++].toFixed(2));
$(this).val(PIDs[5][i++].toFixed(2));
break;
case 2:
$(this).val(PIDs[5][i++].toFixed(3));
$(this).val(PIDs[5][i++].toFixed(3));
break;
}
});
}
});
i = 0;
$('.pid_tuning .NavR input').each(function() {
switch (i) {
case 0:
$(this).val(PIDs[6][i++].toFixed(1));
$(this).val(PIDs[6][i++].toFixed(1));
break;
case 1:
$(this).val(PIDs[6][i++].toFixed(2));
$(this).val(PIDs[6][i++].toFixed(2));
break;
case 2:
$(this).val(PIDs[6][i++].toFixed(3));
$(this).val(PIDs[6][i++].toFixed(3));
break;
}
});
}
});
i = 0;
$('.pid_tuning .LEVEL input').each(function() {
switch (i) {
case 0:
$(this).val(PIDs[7][i++].toFixed(1));
$(this).val(PIDs[7][i++].toFixed(1));
break;
case 1:
$(this).val(PIDs[7][i++].toFixed(2));
$(this).val(PIDs[7][i++].toFixed(2));
break;
case 2:
$(this).val(PIDs[7][i++].toFixed(0));
$(this).val(PIDs[7][i++].toFixed(0));
break;
}
});
}
});
i = 0;
$('.pid_tuning .MAG input').each(function() {
$(this).val(PIDs[8][i++].toFixed(1));
});
$(this).val(PIDs[8][i++].toFixed(1));
});
i = 0;
$('.pid_tuning .Vario input').each(function() {
switch (i) {
case 0:
$(this).val(PIDs[9][i++].toFixed(1));
$(this).val(PIDs[9][i++].toFixed(1));
break;
case 1:
$(this).val(PIDs[9][i++].toFixed(3));
$(this).val(PIDs[9][i++].toFixed(3));
break;
case 2:
$(this).val(PIDs[9][i++].toFixed(0));
$(this).val(PIDs[9][i++].toFixed(0));
break;
}
}
});
// Fill in data from RC_tuning object
$('.rate-tpa input[name="roll-pitch"]').val(RC_tuning.roll_pitch_rate.toFixed(2));
$('.rate-tpa input[name="yaw"]').val(RC_tuning.yaw_rate.toFixed(2));
$('.rate-tpa input[name="tpa"]').val(RC_tuning.dynamic_THR_PID.toFixed(2));
// Fill in currently selected profile
$('input[name="profile"]').val(CONFIG.profile + 1); // +1 because the range is 0-2
// UI Hooks
$('input[name="profile"]').change(function() {
var profile = parseInt($(this).val());
send_message(MSP_codes.MSP_SELECT_SETTING, [profile - 1], false, function() {
GUI.log('Loaded Profile: <strong>' + profile + '</strong>');
GUI.tab_switch_cleanup(function() {
GUI.tab_switch_cleanup(function() {
tab_initialize_pid_tuning();
});
});
});
$('a.refresh').click(function() {
GUI.tab_switch_cleanup(function() {
GUI.log('PID data <strong>refreshed</strong>');
tab_initialize_pid_tuning();
});
});
$('a.update').click(function() {
// Catch all the changes and stuff the inside PIDs array
var i = 0;
$('table.pid_tuning tr.ROLL input').each(function() {
PIDs[0][i++] = parseFloat($(this).val());
});
i = 0;
$('table.pid_tuning tr.PITCH input').each(function() {
PIDs[1][i++] = parseFloat($(this).val());
});
i = 0;
$('table.pid_tuning tr.YAW input').each(function() {
PIDs[2][i++] = parseFloat($(this).val());
});
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;
$('table.pid_tuning tr.LEVEL input').each(function() {
PIDs[7][i++] = parseFloat($(this).val());
});
i = 0;
$('table.pid_tuning tr.MAG input').each(function() {
PIDs[8][i++] = parseFloat($(this).val());
});
var PID_buffer_out = new Array();
for (var i = 0, needle = 0; i < PIDs.length; i++, needle += 3) {
switch (i) {
case 0:
case 1:
case 2:
case 3:
case 7:
case 0:
case 1:
case 2:
case 3:
case 7:
case 8:
case 9:
PID_buffer_out[needle] = parseInt(PIDs[i][0] * 10);
@ -235,23 +235,23 @@ function tab_initialize_pid_tuning() {
PID_buffer_out[needle + 1] = parseInt(PIDs[i][1] * 100);
PID_buffer_out[needle + 2] = parseInt(PIDs[i][2]);
break;
case 5:
case 5:
case 6:
PID_buffer_out[needle] = parseInt(PIDs[i][0] * 10);
PID_buffer_out[needle + 1] = parseInt(PIDs[i][1] * 100);
PID_buffer_out[needle + 2] = parseInt(PIDs[i][2] * 1000);
break;
break;
}
}
// Send over the PID changes
send_message(MSP_codes.MSP_SET_PID, PID_buffer_out);
// catch RC_tuning changes
RC_tuning.roll_pitch_rate = parseFloat($('.rate-tpa input[name="roll-pitch"]').val());
RC_tuning.yaw_rate = parseFloat($('.rate-tpa input[name="yaw"]').val());
RC_tuning.dynamic_THR_PID = parseFloat($('.rate-tpa input[name="tpa"]').val());
RC_tuning.dynamic_THR_PID = parseFloat($('.rate-tpa input[name="tpa"]').val());
var RC_tuning_buffer_out = new Array();
RC_tuning_buffer_out[0] = parseInt(RC_tuning.RC_RATE * 100);
RC_tuning_buffer_out[1] = parseInt(RC_tuning.RC_EXPO * 100);
@ -260,17 +260,17 @@ function tab_initialize_pid_tuning() {
RC_tuning_buffer_out[4] = parseInt(RC_tuning.dynamic_THR_PID * 100);
RC_tuning_buffer_out[5] = parseInt(RC_tuning.throttle_MID * 100);
RC_tuning_buffer_out[6] = parseInt(RC_tuning.throttle_EXPO * 100);
// Send over the RC_tuning changes
send_message(MSP_codes.MSP_SET_RC_TUNING, RC_tuning_buffer_out);
// Save changes to EEPROM
send_message(MSP_codes.MSP_EEPROM_WRITE, MSP_codes.MSP_EEPROM_WRITE, false, function() {
GUI.log('EEPROM <span style="color: green">saved</span>');
var element = $('a.update');
element.addClass('success');
GUI.timeout_add('success_highlight', function() {
element.removeClass('success');
}, 2000);
@ -283,5 +283,5 @@ function tab_initialize_pid_tuning() {
}, 50);
});
});
});
});
}

View file

@ -9,7 +9,7 @@
.tab-receiver .bars ul {
height: 20px;
line-height: 20px;
margin-bottom: 5px;
}
.tab-receiver .bars li {
@ -21,7 +21,7 @@
.tab-receiver .bars .meter meter {
width: 200px;
height: 20px;
border: 1px solid silver;
}
.tab-receiver .bars .value {
@ -49,20 +49,20 @@
}
.tab-receiver .tunings table tr:nth-child(odd) {
background-color: #ececec;
}
}
.tab-receiver .tunings table input {
width: 116px;
height: 20px;
line-height: 20px;
padding: 0 5px 0 5px;
text-align: right;
}
.tab-receiver #RX_plot {
margin: auto;
margin-top: 20px;
width: 880px;
width: 880px;
height: 200px;
}
.tab-receiver .curves {
@ -70,10 +70,10 @@
}
.tab-receiver .throttle_curve {
margin: 0 10px 10px 0;
width: 220px;
height: 58px;
border: 1px solid silver;
}
.tab-receiver .pitch_roll_curve {
@ -81,24 +81,24 @@
width: 220px;
height: 58px;
border: 1px solid silver;
}
.tab-receiver .update,
.tab-receiver .refresh {
display: block;
float: right;
margin-top: 22px;
height: 28px;
line-height: 28px;
padding: 0 15px 0 15px;
text-align: center;
font-weight: bold;
border: 1px solid silver;
background-color: #ececec;
}
@ -115,6 +115,6 @@
.tab-receiver select[name="rx_refresh_rate"] {
float: right;
margin-right: 20px;
border: 1px solid silver;
}

View file

@ -39,7 +39,7 @@
<li class="name">AUX4</li>
<li class="meter"><meter min="900" max="2100"></meter></li>
<li class="value"></li>
</ul>
</ul>
</div>
<div class="tunings">
<table class="throttle">

View file

@ -1,7 +1,7 @@
function tab_initialize_receiver() {
ga_tracker.sendAppView('Receiver Page');
GUI.active_tab = 'receiver';
send_message(MSP_codes.MSP_RC_TUNING, MSP_codes.MSP_RC_TUNING, false, function() {
send_message(MSP_codes.MSP_RC, MSP_codes.MSP_RC, false, function() {
$('#content').load("./tabs/receiver.html", function() {
@ -11,28 +11,28 @@ function tab_initialize_receiver() {
$('.tunings .rate input[name="rate"]').val(RC_tuning.RC_RATE.toFixed(2));
$('.tunings .rate input[name="expo"]').val(RC_tuning.RC_EXPO.toFixed(2));
// Setup plot variables and plot it self
var samples_i = 300;
RX_plot_data = new Array(8);
for (var i = 0; i < 8; i++) {
RX_plot_data[i] = new Array();
}
}
for (var i = 0; i <= 300; i++) {
RX_plot_data[0].push([i, 0]);
RX_plot_data[1].push([i, 0]);
RX_plot_data[2].push([i, 0]);
RX_plot_data[3].push([i, 0]);
RX_plot_data[4].push([i, 0]);
RX_plot_data[5].push([i, 0]);
RX_plot_data[6].push([i, 0]);
RX_plot_data[7].push([i, 0]);
RX_plot_data[4].push([i, 0]);
RX_plot_data[5].push([i, 0]);
RX_plot_data[6].push([i, 0]);
RX_plot_data[7].push([i, 0]);
}
e_RX_plot = document.getElementById("RX_plot");
RX_plot_options = {
title: "Channel width (us)",
shadowSize: 0,
@ -50,9 +50,9 @@ function tab_initialize_receiver() {
legend : {
position: "we",
backgroundOpacity: 0
}
};
}
};
chrome.storage.local.get('rx_refresh_rate', function(result) {
if (typeof result.rx_refresh_rate != 'undefined') {
$('select[name="rx_refresh_rate"]').val(result.rx_refresh_rate).change();
@ -60,49 +60,49 @@ function tab_initialize_receiver() {
$('select[name="rx_refresh_rate"]').change(); // start with default value
}
});
// UI Hooks
// curves
// UI Hooks
// curves
$('.tunings .throttle input').change(function() {
setTimeout(function() {
var mid = parseFloat($('.tunings .throttle input[name="mid"]').val());
var expo = parseFloat($('.tunings .throttle input[name="expo"]').val());
var throttle_curve = $('.throttle_curve canvas').get(0);
var context = throttle_curve.getContext("2d");
context.clearRect(0, 0, 220, 58);
// math magic by englishman
var midx = 220 * mid;
var midxl = midx * .5;
var midxr = (((220 - midx) * .5) + midx);
var midy = 58 - (midx * (58 / 220));
var midyl = 58 - ((58 - midy) * .5 *(expo + 1));
var midyr = (midy / 2) * (expo + 1);
var midyr = (midy / 2) * (expo + 1);
context.beginPath();
context.moveTo(0, 58);
context.quadraticCurveTo(midxl, midyl, midx, midy);
context.moveTo(midx, midy);
context.quadraticCurveTo(midxr, midyr, 220, 0);
context.quadraticCurveTo(midxr, midyr, 220, 0);
context.lineWidth = 2;
context.stroke();
}, 0); // race condition, that should always trigger after all events are processed
}).change();
$('.tunings .rate input').change(function() {
setTimeout(function() {
var rate = parseFloat($('.tunings .rate input[name="rate"]').val());
var expo = parseFloat($('.tunings .rate input[name="expo"]').val());
var expo = parseFloat($('.tunings .rate input[name="expo"]').val());
var pitch_roll_curve = $('.pitch_roll_curve canvas').get(0);
var context = pitch_roll_curve.getContext("2d");
context.clearRect(0, 0, 220, 58);
// math magic by englishman
var ratey = 58 * rate;
context.beginPath();
context.moveTo(0, 58);
context.quadraticCurveTo(110, 58 - ((ratey / 2) * (1 - expo)), 220, 58 - ratey);
@ -110,7 +110,7 @@ function tab_initialize_receiver() {
context.stroke();
}, 0); // race condition, that should always trigger after all events are processed
}).change();
$('a.refresh').click(function() {
send_message(MSP_codes.MSP_RC_TUNING, MSP_codes.MSP_RC_TUNING, false, function() {
// fill in data from RC_tuning
@ -119,21 +119,21 @@ function tab_initialize_receiver() {
$('.tunings .rate input[name="rate"]').val(RC_tuning.RC_RATE.toFixed(2));
$('.tunings .rate input[name="expo"]').val(RC_tuning.RC_EXPO.toFixed(2));
// update visual representation
$('.tunings .throttle input').change();
$('.tunings .rate input').change();
});
});
$('a.update').click(function() {
// catch RC_tuning changes
RC_tuning.throttle_MID = parseFloat($('.tunings .throttle input[name="mid"]').val());
RC_tuning.throttle_EXPO = parseFloat($('.tunings .throttle input[name="expo"]').val());
RC_tuning.RC_RATE = parseFloat($('.tunings .rate input[name="rate"]').val());
RC_tuning.RC_EXPO = parseFloat($('.tunings .rate input[name="expo"]').val());
RC_tuning.RC_EXPO = parseFloat($('.tunings .rate input[name="expo"]').val());
var RC_tuning_buffer_out = new Array();
RC_tuning_buffer_out[0] = parseInt(RC_tuning.RC_RATE * 100);
RC_tuning_buffer_out[1] = parseInt(RC_tuning.RC_EXPO * 100);
@ -142,57 +142,57 @@ function tab_initialize_receiver() {
RC_tuning_buffer_out[4] = parseInt(RC_tuning.dynamic_THR_PID * 100);
RC_tuning_buffer_out[5] = parseInt(RC_tuning.throttle_MID * 100);
RC_tuning_buffer_out[6] = parseInt(RC_tuning.throttle_EXPO * 100);
// Send over the RC_tuning changes
send_message(MSP_codes.MSP_SET_RC_TUNING, RC_tuning_buffer_out);
send_message(MSP_codes.MSP_SET_RC_TUNING, RC_tuning_buffer_out);
// Save changes to EEPROM
send_message(MSP_codes.MSP_EEPROM_WRITE, MSP_codes.MSP_EEPROM_WRITE, false, function() {
GUI.log('EEPROM <span style="color: green">saved</span>');
var element = $('a.update');
element.addClass('success');
GUI.timeout_add('success_highlight', function() {
element.removeClass('success');
}, 2000);
});
});
$('select[name="rx_refresh_rate"]').change(function() {
var plot_update_rate = parseInt($(this).val());
// timer initialization
GUI.interval_remove('receiver_poll');
// enable RC data pulling
GUI.interval_add('receiver_poll', function() {
// Update UI with latest data
$('.tab-receiver meter:eq(0)').val(RC.throttle);
$('.tab-receiver .value:eq(0)').html(RC.throttle);
$('.tab-receiver meter:eq(1)').val(RC.pitch);
$('.tab-receiver .value:eq(1)').html(RC.pitch);
$('.tab-receiver meter:eq(2)').val(RC.roll);
$('.tab-receiver .value:eq(2)').html(RC.roll);
$('.tab-receiver meter:eq(3)').val(RC.yaw);
$('.tab-receiver .value:eq(3)').html(RC.yaw);
$('.tab-receiver meter:eq(4)').val(RC.AUX1);
$('.tab-receiver .value:eq(4)').html(RC.AUX1);
$('.tab-receiver meter:eq(5)').val(RC.AUX2);
$('.tab-receiver .value:eq(5)').html(RC.AUX2);
$('.tab-receiver meter:eq(6)').val(RC.AUX3);
$('.tab-receiver .value:eq(6)').html(RC.AUX3);
$('.tab-receiver meter:eq(7)').val(RC.AUX4);
$('.tab-receiver .value:eq(7)').html(RC.AUX4);
// push latest data to the main array
RX_plot_data[0].push([samples_i, RC.throttle]);
RX_plot_data[1].push([samples_i, RC.pitch]);
@ -201,7 +201,7 @@ function tab_initialize_receiver() {
RX_plot_data[4].push([samples_i, RC.AUX1]);
RX_plot_data[5].push([samples_i, RC.AUX2]);
RX_plot_data[6].push([samples_i, RC.AUX3]);
RX_plot_data[7].push([samples_i, RC.AUX4]);
RX_plot_data[7].push([samples_i, RC.AUX4]);
// Remove old data from array
while (RX_plot_data[0].length > 300) {
@ -214,10 +214,10 @@ function tab_initialize_receiver() {
RX_plot_data[6].shift();
RX_plot_data[7].shift();
};
// redraw plot
Flotr.draw(e_RX_plot, [
{data: RX_plot_data[0], label: "THROTTLE"},
{data: RX_plot_data[0], label: "THROTTLE"},
{data: RX_plot_data[1], label: "PITCH"},
{data: RX_plot_data[2], label: "ROLL"},
{data: RX_plot_data[3], label: "YAW"},
@ -225,17 +225,17 @@ function tab_initialize_receiver() {
{data: RX_plot_data[5], label: "AUX2"},
{data: RX_plot_data[6], label: "AUX3"},
{data: RX_plot_data[7], label: "AUX4"} ], RX_plot_options);
samples_i++;
// Request new data
send_message(MSP_codes.MSP_STATUS, MSP_codes.MSP_STATUS);
send_message(MSP_codes.MSP_RC, MSP_codes.MSP_RC);
}, plot_update_rate, true);
chrome.storage.local.set({'rx_refresh_rate': plot_update_rate});
});
});
});
});

View file

@ -24,20 +24,20 @@
.tab-sensors #debug4 {
height: 120px;
}
.tab-sensors select {
float: right;
border: 1px solid silver;
}
/* Flotr related styles */
.flotr-legend {
.flotr-legend {
padding: 2px;
margin-left: 31px;
top: 20px;
border: 0;
background-color: white;
opacity: 0.75;
}

View file

@ -48,7 +48,7 @@
<option value="250">250 ms</option>
<option value="500">500 ms</option>
<option value="1000">1000 ms</option>
</select>
</select>
<div class="clear-both"></div>
<div id="baro"></div>
<select title="Debug refresh rate" name="debug_refresh_rate">

View file

@ -1,69 +1,69 @@
function tab_initialize_sensors() {
ga_tracker.sendAppView('Sensor Page');
GUI.active_tab = 'sensors';
$('#content').load("./tabs/sensors.html", function() {
// Always start with default/empty sensor data array, clean slate all
for (var i = 0; i < 3; i++) SENSOR_DATA.accelerometer[i] = 0;
for (var i = 0; i < 3; i++) SENSOR_DATA.gyroscope[i] = 0;
for (var i = 0; i < 3; i++) SENSOR_DATA.magnetometer[i] = 0;
for (var i = 0; i < 4; i++) SENSOR_DATA.debug[i] = 0;
// Setup variables
var samples_gyro_i = 300;
var samples_accel_i = 300;
var samples_mag_i = 300;
var samples_baro_i = 300;
var samples_debug_i = 300;
var gyro_data = new Array(3);
var accel_data = new Array(3);
var mag_data = new Array(3);
var baro_data = new Array(1);
var debug_data = new Array(4);
gyro_data[0] = new Array();
gyro_data[1] = new Array();
gyro_data[2] = new Array();
accel_data[0] = new Array();
accel_data[1] = new Array();
accel_data[2] = new Array();
accel_data[2] = new Array();
mag_data[0] = new Array();
mag_data[1] = new Array();
mag_data[2] = new Array();
mag_data[2] = new Array();
baro_data[0] = new Array();
for (var i = 0; i < 4; i++) debug_data[i] = new Array();
for (var i = 0; i <= 300; i++) {
gyro_data[0].push([i, 0]);
gyro_data[1].push([i, 0]);
gyro_data[2].push([i, 0]);
accel_data[0].push([i, 0]);
accel_data[1].push([i, 0]);
accel_data[2].push([i, 0]);
accel_data[2].push([i, 0]);
mag_data[0].push([i, 0]);
mag_data[1].push([i, 0]);
mag_data[2].push([i, 0]);
mag_data[2].push([i, 0]);
baro_data[0].push([i, 0]);
for (var j = 0; j < 4; j++) debug_data[j].push([i, 0]);
}
// plot specific stuff
var e_graph_gyro = document.getElementById("gyro");
var e_graph_accel = document.getElementById("accel");
var e_graph_accel = document.getElementById("accel");
var e_graph_mag = document.getElementById("mag");
var e_graph_baro = document.getElementById("baro");
var e_graph_baro = document.getElementById("baro");
var e_graph_debug1 = document.getElementById("debug1");
var e_graph_debug2 = document.getElementById("debug2");
var e_graph_debug3 = document.getElementById("debug3");
var e_graph_debug4 = document.getElementById("debug4");
var gyro_options = {
title: "Gyroscope (deg/s)",
shadowSize: 0,
@ -83,7 +83,7 @@ function tab_initialize_sensors() {
backgroundOpacity: 0
}
};
var accel_options = {
title: "Accelerometer (g)",
shadowSize: 0,
@ -103,7 +103,7 @@ function tab_initialize_sensors() {
backgroundOpacity: 0
}
};
var mag_options = {
title: "Magnetometer (Ga)",
shadowSize: 0,
@ -121,7 +121,7 @@ function tab_initialize_sensors() {
backgroundOpacity: 0
}
};
var baro_options = {
title: "Barometer (meters)",
shadowSize: 0,
@ -157,7 +157,7 @@ function tab_initialize_sensors() {
backgroundOpacity: 0
}
};
var debug2_options = {};
for (var key in debug1_options) debug2_options[key] = debug1_options[key];
debug2_options.title = "Debug2";
@ -169,81 +169,81 @@ function tab_initialize_sensors() {
var debug4_options = {};
for (var key in debug1_options) debug4_options[key] = debug1_options[key];
debug4_options.title = "Debug4";
// set refresh speeds according to configuration saved in storage
chrome.storage.local.get('sensor_refresh_rates', function(result) {
if (typeof result.sensor_refresh_rates != 'undefined') {
$('.tab-sensors select').eq(0).val(result.sensor_refresh_rates.gyro); // gyro
$('.tab-sensors select').eq(0).val(result.sensor_refresh_rates.gyro); // gyro
$('.tab-sensors select').eq(1).val(result.sensor_refresh_rates.accel); // accel
$('.tab-sensors select').eq(2).val(result.sensor_refresh_rates.mag); // mag
$('.tab-sensors select').eq(3).val(result.sensor_refresh_rates.baro); // baro
$('.tab-sensors select').eq(4).val(result.sensor_refresh_rates.debug); // debug
$('.tab-sensors select').change(); // start polling data by triggering refresh rate change event
} else {
// start polling immediatly (as there is no configuration saved in the storage)
$('.tab-sensors select').change(); // start polling data by triggering refresh rate change event
}
});
$('.tab-sensors select').change(function() {
// if any of the select fields change value, all of the select values are grabbed
// and timers are re-initialized with the new settings
var rates = {
'gyro': parseInt($('.tab-sensors select').eq(0).val()),
'accel': parseInt($('.tab-sensors select').eq(1).val()),
'mag': parseInt($('.tab-sensors select').eq(2).val()),
'gyro': parseInt($('.tab-sensors select').eq(0).val()),
'accel': parseInt($('.tab-sensors select').eq(1).val()),
'mag': parseInt($('.tab-sensors select').eq(2).val()),
'baro': parseInt($('.tab-sensors select').eq(3).val()),
'debug': parseInt($('.tab-sensors select').eq(4).val())
};
// handling of "data pulling" is a little bit funky here, as MSP_RAW_IMU contains values for gyro/accel/mag but not baro
// this means that setting a slower refresh rate on any of the attributes would have no effect
// what we will do instead is = determinate the fastest refresh rate for those 3 attributes, use that as a "polling rate"
// and use the "slower" refresh rates only for re-drawing the graphs (to save resources/computing power)
var fastest = rates.gyro;
if (rates.accel < fastest) {
fastest = rates.accel;
}
if (rates.mag < fastest) {
fastest = rates.mag;
}
// timer initialization
GUI.interval_kill_all(['port_handler', 'port_usage']);
// data pulling timers
GUI.interval_add('status_pull', function() {
send_message(MSP_codes.MSP_STATUS, MSP_codes.MSP_STATUS);
}, 50);
GUI.interval_add('IMU_pull', function() {
send_message(MSP_codes.MSP_RAW_IMU, MSP_codes.MSP_RAW_IMU);
}, fastest);
GUI.interval_add('altitude_pull', function() {
send_message(MSP_codes.MSP_ALTITUDE, MSP_codes.MSP_ALTITUDE);
baro_data[0].push([samples_baro_i, SENSOR_DATA.altitude]);
// Remove old data from array
while (baro_data[0].length > 300) {
baro_data[0].shift();
}
}
Flotr.draw(e_graph_baro, [
Flotr.draw(e_graph_baro, [
{data: baro_data[0], label: "X - meters [" + SENSOR_DATA.altitude.toFixed(2) + "]"} ], baro_options);
samples_baro_i++;
}, rates.baro);
GUI.interval_add('debug_pull', function() {
send_message(MSP_codes.MSP_DEBUG, MSP_codes.MSP_DEBUG);
for (var i = 0; i < 4; i++) {
debug_data[i].push([samples_debug_i, SENSOR_DATA.debug[i]]);
@ -264,68 +264,68 @@ function tab_initialize_sensors() {
samples_debug_i++;
}, rates.debug);
// processing timers
GUI.interval_add('process_gyro', function() {
gyro_data[0].push([samples_gyro_i, SENSOR_DATA.gyroscope[0]]);
gyro_data[1].push([samples_gyro_i, SENSOR_DATA.gyroscope[1]]);
gyro_data[2].push([samples_gyro_i, SENSOR_DATA.gyroscope[2]]);
// Remove old data from array
while (gyro_data[0].length > 300) {
gyro_data[0].shift();
gyro_data[1].shift();
gyro_data[2].shift();
}
}
Flotr.draw(e_graph_gyro, [
{data: gyro_data[0], label: "X - rate [" + SENSOR_DATA.gyroscope[0].toFixed(2) + "]"},
{data: gyro_data[1], label: "Y - rate [" + SENSOR_DATA.gyroscope[1].toFixed(2) + "]"},
{data: gyro_data[2], label: "Z - rate [" + SENSOR_DATA.gyroscope[2].toFixed(2) + "]"} ], gyro_options);
Flotr.draw(e_graph_gyro, [
{data: gyro_data[0], label: "X - rate [" + SENSOR_DATA.gyroscope[0].toFixed(2) + "]"},
{data: gyro_data[1], label: "Y - rate [" + SENSOR_DATA.gyroscope[1].toFixed(2) + "]"},
{data: gyro_data[2], label: "Z - rate [" + SENSOR_DATA.gyroscope[2].toFixed(2) + "]"} ], gyro_options);
samples_gyro_i++;
}, rates.gyro, true);
GUI.interval_add('process_accel', function() {
accel_data[0].push([samples_accel_i, SENSOR_DATA.accelerometer[0]]);
accel_data[1].push([samples_accel_i, SENSOR_DATA.accelerometer[1]]);
accel_data[2].push([samples_accel_i, SENSOR_DATA.accelerometer[2]]);
// Remove old data from array
while (accel_data[0].length > 300) {
while (accel_data[0].length > 300) {
accel_data[0].shift();
accel_data[1].shift();
accel_data[2].shift();
}
accel_data[2].shift();
}
Flotr.draw(e_graph_accel, [
{data: accel_data[1], label: "X - acceleration [" + SENSOR_DATA.accelerometer[0].toFixed(2) + "]"},
{data: accel_data[0], label: "Y - acceleration [" + SENSOR_DATA.accelerometer[1].toFixed(2) + "]"},
Flotr.draw(e_graph_accel, [
{data: accel_data[1], label: "X - acceleration [" + SENSOR_DATA.accelerometer[0].toFixed(2) + "]"},
{data: accel_data[0], label: "Y - acceleration [" + SENSOR_DATA.accelerometer[1].toFixed(2) + "]"},
{data: accel_data[2], label: "Z - acceleration [" + SENSOR_DATA.accelerometer[2].toFixed(2) + "]"} ], accel_options);
samples_accel_i++;
}, rates.accel, true);
GUI.interval_add('process_mag', function() {
mag_data[0].push([samples_mag_i, SENSOR_DATA.magnetometer[0]]);
mag_data[1].push([samples_mag_i, SENSOR_DATA.magnetometer[1]]);
mag_data[2].push([samples_mag_i, SENSOR_DATA.magnetometer[2]]);
// Remove old data from array
while (mag_data[0].length > 300) {
mag_data[0].shift();
mag_data[1].shift();
mag_data[2].shift();
}
}
Flotr.draw(e_graph_mag, [
{data: mag_data[1], label: "X - Ga [" + SENSOR_DATA.magnetometer[0].toFixed(2) + "]"},
{data: mag_data[0], label: "Y - Ga [" + SENSOR_DATA.magnetometer[1].toFixed(2) + "]"},
{data: mag_data[2], label: "Z - Ga [" + SENSOR_DATA.magnetometer[2].toFixed(2) + "]"} ], mag_options);
Flotr.draw(e_graph_mag, [
{data: mag_data[1], label: "X - Ga [" + SENSOR_DATA.magnetometer[0].toFixed(2) + "]"},
{data: mag_data[0], label: "Y - Ga [" + SENSOR_DATA.magnetometer[1].toFixed(2) + "]"},
{data: mag_data[2], label: "Z - Ga [" + SENSOR_DATA.magnetometer[2].toFixed(2) + "]"} ], mag_options);
samples_mag_i++;
}, rates.mag, true);
// store current/latest refresh rates in the storage
chrome.storage.local.set({'sensor_refresh_rates': rates});
});

View file

@ -3,56 +3,56 @@
.tab-servos input[type="number"]::-webkit-inner-spin-button {
border: 0;
}
.tab-servos .supported_wrapper,
.tab-servos .supported_wrapper,
.tab-servos .direction_wrapper {
display: none;
}
.tab-servos .title {
margin-top: 10px;
line-height: 20px;
text-align: center;
font-weight: bold;
border: 1px solid #8b8b8b;
border-bottom: 0;
background-color: #ececec;
}
.tab-servos table.directions td.direction select {
height: 19px;
line-height: 19px;
}
.tab-servos table {
.tab-servos table {
width: 100%;
border-collapse: collapse;
border-collapse: collapse;
}
.tab-servos table th {
line-height: 20px;
text-align: center;
border: 1px solid #8b8b8b;
}
.tab-servos table td {
padding: 1px;
border: 1px solid #8b8b8b;
}
.tab-servos table .main {
font-weight: bold;
text-align: center;
background-color: #ececec;
}
.tab-servos table input[type="number"] {
.tab-servos table input[type="number"] {
width: 65px;
height: 20px;
padding-right: 5px;
line-height: 20px;
text-align: right;
}
.tab-servos table .channel input[type="checkbox"]:first-child {
@ -67,34 +67,34 @@
.tab-servos .direction .name {
float: left;
display: block;
width: 60px;
}
.tab-servos .direction .alternate {
float: left;
display: block;
width: 60px;
}
.tab-servos .direction .first {
float: left;
margin: 2px 10px 0 20px;
}
.tab-servos .direction .second {
float: left;
margin: 2px 10px 0 0;
}
.tab-servos .direction .rate {
width: 200px;
height: 20px;
text-align: center;
}
.tab-servos .live {
float: left;
margin-top: 10px;
}
.tab-servos .live span {
@ -107,17 +107,17 @@
.tab-servos .update {
display: block;
float: right;
margin-top: 10px;
height: 28px;
line-height: 28px;
padding: 0 15px 0 15px;
text-align: center;
font-weight: bold;
border: 1px solid silver;
background-color: #ececec;
}

View file

@ -8,7 +8,7 @@
function tab_initialize_servos() {
ga_tracker.sendAppView('Servos');
GUI.active_tab = 'servos';
// request current Servos Config
send_message(MSP_codes.MSP_IDENT, MSP_codes.MSP_IDENT, false, function() {
send_message(MSP_codes.MSP_SERVO_CONF, MSP_codes.MSP_SERVO_CONF, false, function() {
@ -16,35 +16,35 @@ function tab_initialize_servos() {
$('#content').load("./tabs/servos.html", function() {
// drop previous table
$('div.tab-servos table.fields tr:not(:first)').remove();
var model = $('div.tab-servos strong.model');
var supported_models = [1, 4, 5, 8, 14, 20, 21];
switch (CONFIG.multiType) {
case 1: // TRI
// looking ok so far
model.html('TRI');
process_directions('YAW', 5, 0);
process_servos('Yaw Servo', '', 5, false);
break;
case 4: // BI
// looking ok so far
model.html('BI');
process_directions('L YAW', 4, 1);
process_directions('R YAW', 5, 1);
process_directions('L NICK', 4, 0);
process_directions('R NICK', 5, 0);
process_servos('Left Servo', '', 4, false);
process_servos('Right Servo', '', 5, false);
break;
case 5: // Gimbal
// needs to be verified
model.html('Gimbal');
// rate
process_servos('Pitch Servo', '', 0, 2);
process_servos('Roll Servo', '', 1, 2);
@ -52,18 +52,18 @@ function tab_initialize_servos() {
case 8: // Flying Wing
// looking ok so far
model.html('Flying Wing');
process_directions('L ROLL', 3, 1);
process_directions('R ROLL', 4, 1);
process_directions('L NICK', 3, 0);
process_directions('R NICK', 4, 0);
process_servos('Left Wing', '', 3, false);
process_servos('Right Wing', '', 4, false);
break;
case 14: // Airplane
model.html('Airplane');
// rate
process_servos('Wing 1', '', 3, 2);
process_servos('Wing 2', '', 4, 2);
@ -73,38 +73,38 @@ function tab_initialize_servos() {
case 20: // Dualcopter
// looking ok so far
model.html('Dualcopter');
process_directions('PITCH', 4, 0);
process_directions('ROLL', 5, 0);
process_servos('Roll', '', 5, false);
process_servos('Nick', '', 4, false);
break;
case 21: // Singlecopter
// looking ok so far
model.html('Singlecopter');
process_servos('Right', 'R YAW', 3, true);
process_servos('Left', 'L YAW', 4, true);
process_servos('Front', 'F YAW', 5, true);
process_servos('Rear', 'YAW', 6, true);
break;
default:
model.html("This model doesn't support servos");
// implementation of feature servo_tilt
if (AUX_CONFIG.indexOf('CAMSTAB') > -1 || AUX_CONFIG.indexOf('CAMTRIG') > -1) {
// Gimbal on
// needs to be verified
model.html('Gimbal / Tilt Servos');
// rate
process_servos('Pitch Servo', '', 0, 2);
process_servos('Roll Servo', '', 1, 2);
}
}
// UI hooks for dynamically generated elements
$('table.directions select, table.directions input, table.fields select, table.fields input').change(function() {
if ($('div.live input').is(':checked')) {
@ -112,14 +112,14 @@ function tab_initialize_servos() {
GUI.timeout_add('servos_update', servos_update, 10);
}
});
$('a.update').click(function() {
// standard check for supported_models + custom implementation for feature servo_tilt
if (supported_models.indexOf(CONFIG.multiType) != -1 || AUX_CONFIG.indexOf('CAMSTAB') > -1 || AUX_CONFIG.indexOf('CAMTRIG') > -1) {
servos_update(true);
}
});
// enable data pulling
GUI.interval_add('servos_data_poll', function() {
send_message(MSP_codes.MSP_STATUS, MSP_codes.MSP_STATUS);
@ -135,24 +135,24 @@ function servos_update(save_to_eeprom) {
$('div.tab-servos table.directions tr:not(".main")').each(function() {
var info = $('select', this).data('info');
var val = parseInt($('select', this).val());
// in this stage we need to know which bitfield and which bitposition needs to be flipped
if (val) SERVO_CONFIG[info.obj].rate = bit_set(SERVO_CONFIG[info.obj].rate, info.bitpos);
else SERVO_CONFIG[info.obj].rate = bit_clear(SERVO_CONFIG[info.obj].rate, info.bitpos);
});
// update the rest
$('div.tab-servos table.fields tr:not(".main")').each(function() {
var info = $(this).data('info');
if ($('.middle input', this).is(':disabled')) {
var val = $('.channel input:checked', this).index();
SERVO_CONFIG[info.obj].middle = parseInt(val);
} else {
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());
@ -160,42 +160,42 @@ function servos_update(save_to_eeprom) {
if ($('.direction input', this).length) {
if ($('.direction input:first', this).is(':checked')) SERVO_CONFIG[info.obj].rate = bit_set(SERVO_CONFIG[info.obj].rate, 0);
else SERVO_CONFIG[info.obj].rate = bit_clear(SERVO_CONFIG[info.obj].rate, 0);
if ($('.direction input:last', this).is(':checked')) SERVO_CONFIG[info.obj].rate = bit_set(SERVO_CONFIG[info.obj].rate, 1);
else SERVO_CONFIG[info.obj].rate = bit_clear(SERVO_CONFIG[info.obj].rate, 1);
} else if ($('.direction select', this).length) {
var val = parseInt($('.direction select', this).val());
SERVO_CONFIG[info.obj].rate = val;
SERVO_CONFIG[info.obj].rate = val;
}
});
// send settings over to mcu
var buffer_out = [];
var needle = 0;
for (var i = 0; i < SERVO_CONFIG.length; i++) {
buffer_out[needle++] = lowByte(SERVO_CONFIG[i].min);
buffer_out[needle++] = highByte(SERVO_CONFIG[i].min);
buffer_out[needle++] = lowByte(SERVO_CONFIG[i].max);
buffer_out[needle++] = highByte(SERVO_CONFIG[i].max);
buffer_out[needle++] = lowByte(SERVO_CONFIG[i].middle);
buffer_out[needle++] = highByte(SERVO_CONFIG[i].middle);
buffer_out[needle++] = lowByte(SERVO_CONFIG[i].rate);
}
send_message(MSP_codes.MSP_SET_SERVO_CONF, buffer_out);
if (save_to_eeprom) {
// Save changes to EEPROM
send_message(MSP_codes.MSP_EEPROM_WRITE, MSP_codes.MSP_EEPROM_WRITE, false, function() {
GUI.log('EEPROM <span style="color: green">saved</span>');
var element = $('a.update');
element.addClass('success');
GUI.timeout_add('success_highlight', function() {
element.removeClass('success');
}, 2000);
@ -205,9 +205,9 @@ function servos_update(save_to_eeprom) {
function process_directions(name, obj, bitpos) {
$('div.direction_wrapper').show();
var val;
$('div.tab-servos table.directions').append('\
<tr>\
<td class="name" style="text-align: center">' + name + '</td>\
@ -219,7 +219,7 @@ function process_directions(name, obj, bitpos) {
</td>\
</tr>\
');
if (bit_check(SERVO_CONFIG[obj].rate, bitpos)) val = 1;
else val = 0;
@ -229,7 +229,7 @@ function process_directions(name, obj, bitpos) {
function process_servos(name, alternate, obj, directions) {
$('div.supported_wrapper').show();
$('div.tab-servos table.fields').append('\
<tr> \
<td style="text-align: center">' + name + '</td>\
@ -251,40 +251,40 @@ function process_servos(name, alternate, obj, directions) {
<input class="second" type="checkbox"/><span class="alternate">' + alternate + '</span>\
</td>\
</tr> \
');
');
if (SERVO_CONFIG[obj].middle <= 7) {
$('div.tab-servos table.fields tr:last td.middle input').prop('disabled', true);
$('div.tab-servos table.fields tr:last td.channel').find('input').eq(SERVO_CONFIG[obj].middle).prop('checked', true);
}
if (directions == true) {
$('div.tab-servos table.fields tr:last td.direction input:first').prop('checked', bit_check(SERVO_CONFIG[obj].rate, 0));
$('div.tab-servos table.fields tr:last td.direction input:last').prop('checked', bit_check(SERVO_CONFIG[obj].rate, 1));
} else if (directions == 2) {
// removing checkboxes
$('div.tab-servos table.fields tr:last td.direction').html('');
// adding select box and generating options
$('div.tab-servos table.fields tr:last td.direction').append('\
<select class="rate" name="rate"></select>\
');
var select = $('div.tab-servos table.fields tr:last td.direction select');
for (var i = 100; i > -101; i--) {
select.append('<option value="' + i + '">Rate: ' + i + '%</option>');
}
// select current rate
select.val(SERVO_CONFIG[obj].rate);
} else {
// removing checkboxes
$('div.tab-servos table.fields tr:last td.direction').html('');
}
$('div.tab-servos table.fields tr:last').data('info', {'obj': obj});
// UI hooks
$('div.tab-servos table.fields tr:last td.channel').find('input').click(function() {
if($(this).is(':checked')) {