1
0
Fork 0
mirror of https://github.com/iNavFlight/inav-configurator.git synced 2025-07-14 20:10:11 +03:00
inav-configurator/js/serial.js
Dominic Clifton b4730034c8 Disconnect on F1 boards when 'break' is received if connected. This
happens when the device reboots due to incorrect hardware
initialisation.  This prevents the GUI saying 'waiting for data'.

See https://github.com/cleanflight/cleanflight/pull/1436

Since the problem is already fixed in firmware there's not much reason
to spent development working on additional GUI fixes.  A disconnect will
suffice.
2015-12-16 14:49:58 +01:00

262 lines
No EOL
11 KiB
JavaScript

'use strict';
var serial = {
connectionId: false,
openRequested: false,
openCanceled: false,
bitrate: 0,
bytesReceived: 0,
bytesSent: 0,
failed: 0,
transmitting: false,
outputBuffer: [],
connect: function (path, options, callback) {
var self = this;
self.openRequested = true;
chrome.serial.connect(path, options, function (connectionInfo) {
if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError.message);
}
if (connectionInfo && !self.openCanceled) {
self.connectionId = connectionInfo.connectionId;
self.bitrate = connectionInfo.bitrate;
self.bytesReceived = 0;
self.bytesSent = 0;
self.failed = 0;
self.openRequested = false;
self.onReceive.addListener(function log_bytesReceived(info) {
self.bytesReceived += info.data.byteLength;
});
self.onReceiveError.addListener(function watch_for_on_receive_errors(info) {
console.error(info);
googleAnalytics.sendException('Serial: ' + info.error, false);
switch (info.error) {
case 'system_error': // we might be able to recover from this one
if (!self.failed++) {
chrome.serial.setPaused(self.connectionId, false, function () {
self.getInfo(function (info) {
if (info) {
if (!info.paused) {
console.log('SERIAL: Connection recovered from last onReceiveError');
googleAnalytics.sendException('Serial: onReceiveError - recovered', false);
self.failed = 0;
} else {
console.log('SERIAL: Connection did not recover from last onReceiveError, disconnecting');
GUI.log('Unrecoverable <span style="color: red">failure</span> of serial connection, disconnecting...');
googleAnalytics.sendException('Serial: onReceiveError - unrecoverable', false);
if (GUI.connected_to || GUI.connecting_to) {
$('a.connect').click();
} else {
self.disconnect();
}
}
} else {
if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError.message);
}
}
});
});
}
break;
case 'break':
// This occurs on F1 boards with old firmware.
if (GUI.connected_to || GUI.connecting_to) {
$('a.connect').click();
}
break;
case 'timeout':
// TODO
break;
case 'device_lost':
// TODO
break;
case 'disconnected':
// TODO
break;
}
});
console.log('SERIAL: Connection opened with ID: ' + connectionInfo.connectionId + ', Baud: ' + connectionInfo.bitrate);
if (callback) callback(connectionInfo);
} else if (connectionInfo && self.openCanceled) {
// connection opened, but this connect sequence was canceled
// we will disconnect without triggering any callbacks
self.connectionId = connectionInfo.connectionId;
console.log('SERIAL: Connection opened with ID: ' + connectionInfo.connectionId + ', but request was canceled, disconnecting');
// some bluetooth dongles/dongle drivers really doesn't like to be closed instantly, adding a small delay
setTimeout(function initialization() {
self.openRequested = false;
self.openCanceled = false;
self.disconnect(function resetUI() {
if (callback) callback(false);
});
}, 150);
} else if (self.openCanceled) {
// connection didn't open and sequence was canceled, so we will do nothing
console.log('SERIAL: Connection didn\'t open and request was canceled');
self.openRequested = false;
self.openCanceled = false;
if (callback) callback(false);
} else {
self.openRequested = false;
console.log('SERIAL: Failed to open serial port');
googleAnalytics.sendException('Serial: FailedToOpen', false);
if (callback) callback(false);
}
});
},
disconnect: function (callback) {
var self = this;
if (self.connectionId) {
self.emptyOutputBuffer();
// remove listeners
for (var i = (self.onReceive.listeners.length - 1); i >= 0; i--) {
self.onReceive.removeListener(self.onReceive.listeners[i]);
}
for (var i = (self.onReceiveError.listeners.length - 1); i >= 0; i--) {
self.onReceiveError.removeListener(self.onReceiveError.listeners[i]);
}
chrome.serial.disconnect(this.connectionId, function (result) {
if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError.message);
}
if (result) {
console.log('SERIAL: Connection with ID: ' + self.connectionId + ' closed, Sent: ' + self.bytesSent + ' bytes, Received: ' + self.bytesReceived + ' bytes');
} else {
console.log('SERIAL: Failed to close connection with ID: ' + self.connectionId + ' closed, Sent: ' + self.bytesSent + ' bytes, Received: ' + self.bytesReceived + ' bytes');
googleAnalytics.sendException('Serial: FailedToClose', false);
}
self.connectionId = false;
self.bitrate = 0;
if (callback) callback(result);
});
} else {
// connection wasn't opened, so we won't try to close anything
// instead we will rise canceled flag which will prevent connect from continueing further after being canceled
self.openCanceled = true;
}
},
getDevices: function (callback) {
chrome.serial.getDevices(function (devices_array) {
var devices = [];
devices_array.forEach(function (device) {
devices.push(device.path);
});
callback(devices);
});
},
getInfo: function (callback) {
chrome.serial.getInfo(this.connectionId, callback);
},
getControlSignals: function (callback) {
chrome.serial.getControlSignals(this.connectionId, callback);
},
setControlSignals: function (signals, callback) {
chrome.serial.setControlSignals(this.connectionId, signals, callback);
},
send: function (data, callback) {
var self = this;
this.outputBuffer.push({'data': data, 'callback': callback});
function send() {
// store inside separate variables in case array gets destroyed
var data = self.outputBuffer[0].data,
callback = self.outputBuffer[0].callback;
chrome.serial.send(self.connectionId, data, function (sendInfo) {
// track sent bytes for statistics
self.bytesSent += sendInfo.bytesSent;
// fire callback
if (callback) callback(sendInfo);
// remove data for current transmission form the buffer
self.outputBuffer.shift();
// if there is any data in the queue fire send immediately, otherwise stop trasmitting
if (self.outputBuffer.length) {
// keep the buffer withing reasonable limits
if (self.outputBuffer.length > 100) {
var counter = 0;
while (self.outputBuffer.length > 100) {
self.outputBuffer.pop();
counter++;
}
console.log('SERIAL: Send buffer overflowing, dropped: ' + counter + ' entries');
}
send();
} else {
self.transmitting = false;
}
});
}
if (!this.transmitting) {
this.transmitting = true;
send();
}
},
onReceive: {
listeners: [],
addListener: function (function_reference) {
chrome.serial.onReceive.addListener(function_reference);
this.listeners.push(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;
}
}
}
},
onReceiveError: {
listeners: [],
addListener: function (function_reference) {
chrome.serial.onReceiveError.addListener(function_reference);
this.listeners.push(function_reference);
},
removeListener: function (function_reference) {
for (var i = (this.listeners.length - 1); i >= 0; i--) {
if (this.listeners[i] == function_reference) {
chrome.serial.onReceiveError.removeListener(function_reference);
this.listeners.splice(i, 1);
break;
}
}
}
},
emptyOutputBuffer: function () {
this.outputBuffer = [];
this.transmitting = false;
}
};