|
|
|
'use strict';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @typedef {{state: number, message_direction: number, code: number, message_length_expected: number, message_length_received: number, message_buffer: null, message_buffer_uint8_view: null, message_checksum: number, callbacks: Array, packet_error: number, unsupported: number, ledDirectionLetters: [*], ledFunctionLetters: [*], ledBaseFunctionLetters: [*], ledOverlayLetters: [*], last_received_timestamp: null, analog_last_received_timestamp: number, read: MSP.read, send_message: MSP.send_message, promise: MSP.promise, callbacks_cleanup: MSP.callbacks_cleanup, disconnect_cleanup: MSP.disconnect_cleanup}} MSP
|
|
|
|
*/
|
|
|
|
var MSP = {
|
|
|
|
state: 0,
|
|
|
|
message_direction: 1,
|
|
|
|
code: 0,
|
|
|
|
message_length_expected: 0,
|
|
|
|
message_length_received: 0,
|
|
|
|
message_buffer: null,
|
|
|
|
message_buffer_uint8_view: null,
|
|
|
|
message_checksum: 0,
|
|
|
|
callbacks: [],
|
|
|
|
packet_error: 0,
|
|
|
|
unsupported: 0,
|
|
|
|
|
|
|
|
ledDirectionLetters: ['n', 'e', 's', 'w', 'u', 'd'], // in LSB bit order
|
|
|
|
ledFunctionLetters: ['i', 'w', 'f', 'a', 't', 'r', 'c', 'g', 's', 'b', 'l'], // in LSB bit order
|
|
|
|
ledBaseFunctionLetters: ['c', 'f', 'a', 'l', 's', 'g', 'r'], // in LSB bit
|
|
|
|
ledOverlayLetters: ['t', 'o', 'b', 'n', 'i', 'w'], // in LSB bit
|
|
|
|
|
|
|
|
last_received_timestamp: null,
|
|
|
|
analog_last_received_timestamp: null,
|
|
|
|
|
|
|
|
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
|
|
|
|
if (data[i] == 36) { // $
|
|
|
|
this.state++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 1: // sync char 2
|
|
|
|
if (data[i] == 77) { // M
|
|
|
|
this.state++;
|
|
|
|
} else { // restart and try again
|
|
|
|
this.state = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2: // direction (should be >)
|
|
|
|
this.unsupported = 0;
|
|
|
|
if (data[i] == 62) { // >
|
|
|
|
this.message_direction = 1;
|
|
|
|
} else if (data[i] == 60) { // <
|
|
|
|
this.message_direction = 0;
|
|
|
|
} else if (data[i] == 33) { // !
|
|
|
|
// FC reports unsupported message error
|
|
|
|
this.unsupported = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
|
|
|
// process payload
|
|
|
|
this.state++;
|
|
|
|
} else {
|
|
|
|
// no payload
|
|
|
|
this.state += 2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 5: // payload
|
|
|
|
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++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
if (this.message_checksum == data[i]) {
|
|
|
|
// message received, process
|
|
|
|
mspHelper.processData(this);
|
|
|
|
} else {
|
|
|
|
console.log('code: ' + this.code + ' - crc failed');
|
|
|
|
console.log(data);
|
|
|
|
|
|
|
|
this.packet_error++;
|
|
|
|
$('span.packet-error').html(this.packet_error);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reset variables
|
|
|
|
this.message_length_received = 0;
|
|
|
|
this.state = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
console.log('Unknown state detected: ' + this.state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.last_received_timestamp = Date.now();
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {MSP} mspData
|
|
|
|
*/
|
|
|
|
putCallback: function (mspData) {
|
|
|
|
MSP.callbacks.push(mspData);
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {number} code
|
|
|
|
*/
|
|
|
|
removeCallback: function (code) {
|
|
|
|
|
|
|
|
for (var i in this.callbacks) {
|
|
|
|
if (this.callbacks.hasOwnProperty(i) && this.callbacks[i].code == code) {
|
|
|
|
clearTimeout(this.callbacks[i].timer);
|
|
|
|
this.callbacks.splice(i, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
send_message: function (code, data, callback_sent, callback_msp) {
|
|
|
|
var bufferOut,
|
|
|
|
bufView,
|
|
|
|
i;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For debug reasons, check how ofter MSP frames are executed
|
|
|
|
*/
|
|
|
|
helper.eventFrequencyAnalyzer.put(code);
|
|
|
|
|
|
|
|
// always reserve 6 bytes for protocol overhead !
|
|
|
|
if (data) {
|
|
|
|
var size = data.length + 6,
|
|
|
|
checksum;
|
|
|
|
|
|
|
|
bufferOut = new ArrayBuffer(size);
|
|
|
|
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 (i = 0; i < data.length; i++) {
|
|
|
|
bufView[i + 5] = data[i];
|
|
|
|
|
|
|
|
checksum ^= bufView[i + 5];
|
|
|
|
}
|
|
|
|
|
|
|
|
bufView[5 + data.length] = checksum;
|
|
|
|
} else {
|
|
|
|
bufferOut = new ArrayBuffer(6);
|
|
|
|
bufView = new Uint8Array(bufferOut);
|
|
|
|
|
|
|
|
bufView[0] = 36; // $
|
|
|
|
bufView[1] = 77; // M
|
|
|
|
bufView[2] = 60; // <
|
|
|
|
bufView[3] = 0; // data length
|
|
|
|
bufView[4] = code; // code
|
|
|
|
bufView[5] = bufView[3] ^ bufView[4]; // checksum
|
|
|
|
}
|
|
|
|
|
|
|
|
// dev version 0.57 code below got recently changed due to the fact that queueing same MSP codes was unsupported
|
|
|
|
// and was causing trouble while backup/restoring configurations
|
|
|
|
// watch out if the recent change create any inconsistencies and then adjust accordingly
|
|
|
|
var obj = {
|
|
|
|
'code': code,
|
|
|
|
'requestBuffer': bufferOut,
|
|
|
|
'callback': (callback_msp) ? callback_msp : false,
|
|
|
|
'onSend': callback_sent,
|
|
|
|
'timer': false
|
|
|
|
};
|
|
|
|
|
|
|
|
helper.mspQueue.put(obj);
|
|
|
|
|
|
|
|
// var requestExists = false;
|
|
|
|
// for (i = 0; i < MSP.callbacks.length; i++) {
|
|
|
|
// if (i < MSP.callbacks.length) {
|
|
|
|
// if (MSP.callbacks[i].code == code) {
|
|
|
|
// // request already exist, we will just attach
|
|
|
|
// requestExists = true;
|
|
|
|
// break;
|
|
|
|
// }
|
|
|
|
// } else {
|
|
|
|
// console.log("Callback index error: "+ i);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
// if (!requestExists) {
|
|
|
|
// obj.timer = setInterval(function () {
|
|
|
|
// console.log('MSP data request timed-out: ' + code);
|
|
|
|
//
|
|
|
|
// serial.send(bufferOut, false);
|
|
|
|
// }, serial.getTimeout()); // we should be able to define timeout in the future
|
|
|
|
// }
|
|
|
|
|
|
|
|
// MSP.callbacks.push(obj);
|
|
|
|
|
|
|
|
// always send messages with data payload (even when there is a message already in the queue)
|
|
|
|
// if (data || !requestExists) {
|
|
|
|
// serial.send(bufferOut, function (sendInfo) {
|
|
|
|
// if (sendInfo.bytesSent == bufferOut.byteLength) {
|
|
|
|
// if (callback_sent) callback_sent();
|
|
|
|
// }
|
|
|
|
// });
|
|
|
|
// }
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
promise: function(code, data) {
|
|
|
|
var self = this;
|
|
|
|
return new Promise(function(resolve) {
|
|
|
|
self.send_message(code, data, false, function(data) {
|
|
|
|
resolve(data);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
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.SDCARD_STATE_NOT_PRESENT = 0;
|
|
|
|
MSP.SDCARD_STATE_FATAL = 1;
|
|
|
|
MSP.SDCARD_STATE_CARD_INIT = 2;
|
|
|
|
MSP.SDCARD_STATE_FS_INIT = 3;
|
|
|
|
MSP.SDCARD_STATE_READY = 4;
|