2014-08-09 17:38:46 +00:00
'use strict' ;
2014-01-18 10:44:43 +00:00
var serial = {
2014-11-22 05:31:46 +00:00
connectionId : false ,
openRequested : false ,
openCanceled : false ,
2014-11-21 12:50:02 +00:00
bitrate : 0 ,
2014-11-22 05:54:25 +00:00
bytesReceived : 0 ,
bytesSent : 0 ,
2014-11-21 12:50:02 +00:00
failed : 0 ,
2014-03-08 05:25:15 +00:00
2014-03-28 23:59:39 +00:00
transmitting : false ,
2014-11-22 05:31:46 +00:00
outputBuffer : [ ] ,
2014-03-08 05:25:15 +00:00
2014-09-09 11:55:58 +00:00
connect : function ( path , options , callback ) {
2014-01-18 10:44:43 +00:00
var self = this ;
2014-11-22 05:31:46 +00:00
self . openRequested = true ;
2014-03-08 05:25:15 +00:00
2014-09-09 11:55:58 +00:00
chrome . serial . connect ( path , options , function ( connectionInfo ) {
2014-11-22 05:31:46 +00:00
if ( chrome . runtime . lastError ) {
console . error ( chrome . runtime . lastError . message ) ;
}
if ( connectionInfo && ! self . openCanceled ) {
2014-02-03 09:02:49 +00:00
self . connectionId = connectionInfo . connectionId ;
2014-03-28 23:59:39 +00:00
self . bitrate = connectionInfo . bitrate ;
2014-11-22 05:31:46 +00:00
self . bytesReceived = 0 ;
self . bytesSent = 0 ;
2014-09-14 12:08:28 +00:00
self . failed = 0 ;
2014-11-22 05:31:46 +00:00
self . openRequested = false ;
2014-03-08 05:25:15 +00:00
2014-11-22 05:31:46 +00:00
self . onReceive . addListener ( function log _bytesReceived ( info ) {
self . bytesReceived += info . data . byteLength ;
2014-02-03 09:02:49 +00:00
} ) ;
2014-03-08 05:25:15 +00:00
2014-06-28 12:25:11 +00:00
self . onReceiveError . addListener ( function watch _for _on _receive _errors ( info ) {
console . error ( info ) ;
2014-07-16 11:07:24 +00:00
googleAnalytics . sendException ( 'Serial: ' + info . error , false ) ;
2014-06-28 12:25:11 +00:00
2014-08-09 17:38:46 +00:00
switch ( info . error ) {
case 'system_error' : // we might be able to recover from this one
2014-09-14 12:08:28 +00:00
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 ) ;
2014-09-01 12:56:13 +00:00
2014-09-14 12:08:28 +00:00
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 ( ) ;
}
}
2014-09-01 12:56:13 +00:00
} else {
2014-09-14 12:08:28 +00:00
if ( chrome . runtime . lastError ) {
console . error ( chrome . runtime . lastError . message ) ;
}
2014-09-01 12:56:13 +00:00
}
2014-09-14 12:08:28 +00:00
} ) ;
} ) ;
2014-08-09 18:40:40 +00:00
}
2014-07-01 10:48:20 +00:00
break ;
case 'timeout' :
// TODO
break ;
case 'device_lost' :
// TODO
break ;
case 'disconnected' :
// TODO
break ;
2014-07-01 02:13:33 +00:00
}
2014-06-28 12:25:11 +00:00
} ) ;
2014-01-25 12:48:31 +00:00
console . log ( 'SERIAL: Connection opened with ID: ' + connectionInfo . connectionId + ', Baud: ' + connectionInfo . bitrate ) ;
2014-03-08 05:25:15 +00:00
2014-07-01 02:13:33 +00:00
if ( callback ) callback ( connectionInfo ) ;
2014-11-22 05:31:46 +00:00
} else if ( connectionInfo && self . openCanceled ) {
2014-11-21 12:50:02 +00:00
// 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 ( ) {
2014-11-22 05:31:46 +00:00
self . openRequested = false ;
self . openCanceled = false ;
2014-11-21 12:50:02 +00:00
self . disconnect ( function resetUI ( ) {
if ( callback ) callback ( false ) ;
} ) ;
} , 150 ) ;
2014-11-22 05:31:46 +00:00
} else if ( self . openCanceled ) {
2014-11-21 12:50:02 +00:00
// connection didn't open and sequence was canceled, so we will do nothing
console . log ( 'SERIAL: Connection didn\'t open and request was canceled' ) ;
2014-11-22 05:31:46 +00:00
self . openRequested = false ;
self . openCanceled = false ;
2014-11-21 12:50:02 +00:00
if ( callback ) callback ( false ) ;
2014-02-03 09:02:49 +00:00
} else {
2014-11-22 05:31:46 +00:00
self . openRequested = false ;
2014-02-03 09:02:49 +00:00
console . log ( 'SERIAL: Failed to open serial port' ) ;
2014-07-16 11:07:24 +00:00
googleAnalytics . sendException ( 'Serial: FailedToOpen' , false ) ;
2014-07-01 02:13:33 +00:00
if ( callback ) callback ( false ) ;
2014-01-25 12:48:31 +00:00
}
2014-01-18 10:44:43 +00:00
} ) ;
} ,
2014-09-09 11:55:58 +00:00
disconnect : function ( callback ) {
2014-01-18 10:44:43 +00:00
var self = this ;
2014-03-08 05:25:15 +00:00
2014-11-22 05:31:46 +00:00
if ( self . connectionId ) {
2014-12-05 09:23:53 +00:00
self . emptyOutputBuffer ( ) ;
2014-01-27 00:48:34 +00:00
2014-11-21 12:50:02 +00:00
// remove listeners
for ( var i = ( self . onReceive . listeners . length - 1 ) ; i >= 0 ; i -- ) {
self . onReceive . removeListener ( self . onReceive . listeners [ i ] ) ;
}
2014-06-28 12:25:11 +00:00
2014-11-21 12:50:02 +00:00
for ( var i = ( self . onReceiveError . listeners . length - 1 ) ; i >= 0 ; i -- ) {
self . onReceiveError . removeListener ( self . onReceiveError . listeners [ i ] ) ;
2014-01-25 12:48:31 +00:00
}
2014-03-08 05:25:15 +00:00
2014-11-21 12:50:02 +00:00
chrome . serial . disconnect ( this . connectionId , function ( result ) {
2014-11-22 05:31:46 +00:00
if ( chrome . runtime . lastError ) {
console . error ( chrome . runtime . lastError . message ) ;
}
2014-11-21 12:50:02 +00:00
if ( result ) {
2014-11-22 05:31:46 +00:00
console . log ( 'SERIAL: Connection with ID: ' + self . connectionId + ' closed, Sent: ' + self . bytesSent + ' bytes, Received: ' + self . bytesReceived + ' bytes' ) ;
2014-11-21 12:50:02 +00:00
} else {
2014-11-22 05:31:46 +00:00
console . log ( 'SERIAL: Failed to close connection with ID: ' + self . connectionId + ' closed, Sent: ' + self . bytesSent + ' bytes, Received: ' + self . bytesReceived + ' bytes' ) ;
2014-11-21 12:50:02 +00:00
googleAnalytics . sendException ( 'Serial: FailedToClose' , false ) ;
}
2014-03-08 05:25:15 +00:00
2014-11-22 05:31:46 +00:00
self . connectionId = false ;
2014-11-21 12:50:02 +00:00
self . bitrate = 0 ;
2014-03-08 05:25:15 +00:00
2014-11-21 12:50:02 +00:00
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
2014-11-22 05:31:46 +00:00
self . openCanceled = true ;
2014-11-21 12:50:02 +00:00
}
2014-01-18 10:44:43 +00:00
} ,
2014-09-09 11:55:58 +00:00
getDevices : function ( callback ) {
chrome . serial . getDevices ( function ( devices _array ) {
2014-01-18 10:44:43 +00:00
var devices = [ ] ;
2014-09-09 11:55:58 +00:00
devices _array . forEach ( function ( device ) {
2014-01-18 10:44:43 +00:00
devices . push ( device . path ) ;
} ) ;
2014-03-08 05:25:15 +00:00
2014-01-18 10:44:43 +00:00
callback ( devices ) ;
} ) ;
} ,
2014-09-09 11:55:58 +00:00
getInfo : function ( callback ) {
2014-07-01 10:48:20 +00:00
chrome . serial . getInfo ( this . connectionId , callback ) ;
} ,
2014-09-09 11:55:58 +00:00
getControlSignals : function ( callback ) {
2014-05-02 23:03:24 +00:00
chrome . serial . getControlSignals ( this . connectionId , callback ) ;
} ,
2014-09-09 11:55:58 +00:00
setControlSignals : function ( signals , callback ) {
2014-07-16 12:06:15 +00:00
chrome . serial . setControlSignals ( this . connectionId , signals , callback ) ;
} ,
2014-09-09 11:55:58 +00:00
send : function ( data , callback ) {
2014-01-26 19:01:46 +00:00
var self = this ;
2014-11-22 05:31:46 +00:00
this . outputBuffer . push ( { 'data' : data , 'callback' : callback } ) ;
2014-03-08 05:25:15 +00:00
2014-11-22 05:31:46 +00:00
function send ( ) {
// store inside separate variables in case array gets destroyed
var data = self . outputBuffer [ 0 ] . data ,
callback = self . outputBuffer [ 0 ] . callback ;
2014-03-08 05:25:15 +00:00
2014-11-22 05:31:46 +00:00
chrome . serial . send ( self . connectionId , data , function ( sendInfo ) {
// track sent bytes for statistics
self . bytesSent += sendInfo . bytesSent ;
2014-09-13 13:01:32 +00:00
2014-11-22 05:31:46 +00:00
// fire callback
if ( callback ) callback ( sendInfo ) ;
2014-03-08 05:25:15 +00:00
2014-11-22 05:31:46 +00:00
// remove data for current transmission form the buffer
self . outputBuffer . shift ( ) ;
2014-03-08 05:25:15 +00:00
2014-11-22 05:31:46 +00:00
// 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 ;
2014-09-13 13:01:32 +00:00
2014-11-22 05:31:46 +00:00
while ( self . outputBuffer . length > 100 ) {
self . outputBuffer . pop ( ) ;
counter ++ ;
2014-08-09 18:40:40 +00:00
}
2014-03-08 05:25:15 +00:00
2014-11-22 05:31:46 +00:00
console . log ( 'SERIAL: Send buffer overflowing, dropped: ' + counter + ' entries' ) ;
2014-08-09 18:40:40 +00:00
}
2014-03-08 05:25:15 +00:00
2014-11-22 05:31:46 +00:00
send ( ) ;
} else {
self . transmitting = false ;
}
} ) ;
}
if ( ! this . transmitting ) {
this . transmitting = true ;
2014-09-13 13:01:32 +00:00
send ( ) ;
2014-01-26 19:01:46 +00:00
}
2014-01-18 10:44:43 +00:00
} ,
2014-01-31 14:51:47 +00:00
onReceive : {
listeners : [ ] ,
2014-03-08 05:25:15 +00:00
2014-09-09 11:55:58 +00:00
addListener : function ( function _reference ) {
chrome . serial . onReceive . addListener ( function _reference ) ;
2014-01-31 14:51:47 +00:00
this . listeners . push ( function _reference ) ;
} ,
2014-09-09 11:55:58 +00:00
removeListener : function ( function _reference ) {
2014-01-31 14:51:47 +00:00
for ( var i = ( this . listeners . length - 1 ) ; i >= 0 ; i -- ) {
if ( this . listeners [ i ] == function _reference ) {
chrome . serial . onReceive . removeListener ( function _reference ) ;
2014-03-08 05:25:15 +00:00
2014-01-31 14:51:47 +00:00
this . listeners . splice ( i , 1 ) ;
break ;
}
2014-03-08 05:25:15 +00:00
}
2014-01-31 14:51:47 +00:00
}
} ,
2014-06-28 12:25:11 +00:00
onReceiveError : {
listeners : [ ] ,
2014-09-09 11:55:58 +00:00
addListener : function ( function _reference ) {
chrome . serial . onReceiveError . addListener ( function _reference ) ;
2014-06-28 12:25:11 +00:00
this . listeners . push ( function _reference ) ;
} ,
2014-09-09 11:55:58 +00:00
removeListener : function ( function _reference ) {
2014-06-28 12:25:11 +00:00
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 ;
}
}
}
} ,
2014-12-05 09:23:53 +00:00
emptyOutputBuffer : function ( ) {
2014-11-22 05:31:46 +00:00
this . outputBuffer = [ ] ;
2014-01-26 20:37:19 +00:00
this . transmitting = false ;
2014-01-18 10:44:43 +00:00
}
} ;