2013-09-05 16:02:48 +02:00
/ * *
* Copyright 2013 IBM Corp .
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* * /
var RED = require ( "../../red/red" ) ;
2013-11-03 20:09:45 +01:00
var settings = RED . settings ;
2013-09-05 16:02:48 +02:00
var events = require ( "events" ) ;
var util = require ( "util" ) ;
var serialp = require ( "serialport" ) ;
// TODO: 'serialPool' should be encapsulated in SerialPortNode
function SerialPortNode ( n ) {
RED . nodes . createNode ( this , n ) ;
this . serialport = n . serialport ;
this . serialbaud = n . serialbaud * 1 ;
this . newline = n . newline ;
}
RED . nodes . registerType ( "serial-port" , SerialPortNode ) ;
function SerialOutNode ( n ) {
RED . nodes . createNode ( this , n ) ;
this . serial = n . serial ;
this . serialConfig = RED . nodes . getNode ( this . serial ) ;
if ( this . serialConfig ) {
var node = this ;
try {
node . port = serialPool . get ( this . serialConfig . serialport , this . serialConfig . serialbaud , this . serialConfig . newline ) ;
} catch ( err ) {
this . error ( err ) ;
return ;
}
2013-09-25 16:18:55 +02:00
node . on ( "input" , function ( msg ) {
2013-09-05 16:02:48 +02:00
//console.log("{",msg,"}");
node . port . write ( msg . payload , function ( err , res ) {
2013-09-25 16:18:55 +02:00
if ( err ) {
node . error ( err ) ;
}
2013-09-05 16:02:48 +02:00
} ) ;
} ) ;
} else {
this . error ( "missing serial config" ) ;
}
}
RED . nodes . registerType ( "serial out" , SerialOutNode ) ;
2013-11-03 20:09:45 +01:00
2013-09-05 16:02:48 +02:00
SerialOutNode . prototype . close = function ( ) {
if ( this . serialConfig ) {
serialPool . close ( this . serialConfig . serialport ) ;
}
}
function SerialInNode ( n ) {
RED . nodes . createNode ( this , n ) ;
this . serial = n . serial ;
this . serialConfig = RED . nodes . getNode ( this . serial ) ;
if ( this . serialConfig ) {
var node = this ;
try {
this . port = serialPool . get ( this . serialConfig . serialport , this . serialConfig . serialbaud , this . serialConfig . newline ) ;
} catch ( err ) {
this . error ( err ) ;
return ;
}
this . port . on ( 'data' , function ( msg ) {
// console.log("{",msg,"}");
var m = { "payload" : msg } ;
node . send ( m ) ;
} ) ;
} else {
this . error ( "missing serial config" ) ;
}
}
RED . nodes . registerType ( "serial in" , SerialInNode ) ;
2013-11-03 20:09:45 +01:00
2013-09-05 16:02:48 +02:00
SerialInNode . prototype . close = function ( ) {
if ( this . serialConfig ) {
try {
serialPool . close ( this . serialConfig . serialport ) ;
} catch ( err ) {
}
this . warn ( "Deploying with serial-port nodes is known to occasionally cause Node-RED to hang. This is due to an open issue with the underlying module." ) ;
}
}
var serialPool = function ( ) {
var connections = { } ;
return {
get : function ( port , baud , newline , callback ) {
var id = port ;
if ( ! connections [ id ] ) {
connections [ id ] = function ( ) {
var obj = {
_emitter : new events . EventEmitter ( ) ,
serial : null ,
_closing : false ,
tout : null ,
on : function ( a , b ) { this . _emitter . on ( a , b ) ; } ,
close : function ( cb ) { this . serial . close ( cb ) } ,
write : function ( m , cb ) { this . serial . write ( m , cb ) } ,
}
newline = newline . replace ( "\\n" , "\n" ) . replace ( "\\r" , "\r" ) ;
var setupSerial = function ( ) {
2013-11-03 20:09:45 +01:00
try {
if ( newline == "" ) {
obj . serial = new serialp . SerialPort ( port , {
baudrate : baud ,
parser : serialp . parsers . raw
} ) ;
}
else {
obj . serial = new serialp . SerialPort ( port , {
baudrate : baud ,
parser : serialp . parsers . readline ( newline )
} ) ;
}
obj . serial . on ( 'error' , function ( err ) {
util . log ( "[serial] serial port " + port + " error " + err ) ;
2013-09-05 16:02:48 +02:00
obj . tout = setTimeout ( function ( ) {
setupSerial ( ) ;
} , settings . serialReconnectTime ) ;
2013-11-03 20:09:45 +01:00
} ) ;
obj . serial . on ( 'close' , function ( ) {
if ( ! obj . _closing ) {
util . log ( "[serial] serial port " + port + " closed unexpectedly" ) ;
obj . tout = setTimeout ( function ( ) {
setupSerial ( ) ;
} , settings . serialReconnectTime ) ;
}
} ) ;
obj . serial . on ( 'open' , function ( ) {
util . log ( "[serial] serial port " + port + " opened at " + baud + " baud" ) ;
obj . serial . flush ( ) ;
obj . _emitter . emit ( 'ready' ) ;
} ) ;
obj . serial . on ( 'data' , function ( d ) {
if ( typeof d !== "string" ) {
d = d . toString ( ) ;
for ( i = 0 ; i < d . length ; i ++ ) {
obj . _emitter . emit ( 'data' , d . charAt ( i ) ) ;
}
}
else {
obj . _emitter . emit ( 'data' , d ) ;
2013-09-05 16:02:48 +02:00
}
2013-11-03 20:09:45 +01:00
} ) ;
} catch ( err ) { console . log ( "Booo!" , err , "Booo!" ) ; }
2013-09-05 16:02:48 +02:00
}
setupSerial ( ) ;
return obj ;
} ( ) ;
}
return connections [ id ] ;
} ,
close : function ( port ) {
if ( connections [ port ] ) {
if ( connections [ port ] . tout != null ) clearTimeout ( connections [ port ] . tout ) ;
connections [ port ] . _closing = true ;
try {
connections [ port ] . close ( function ( ) {
util . log ( "[serial] serial port closed" ) ;
} ) ;
2013-11-03 20:09:45 +01:00
} catch ( err ) { } ;
2013-09-05 16:02:48 +02:00
}
delete connections [ port ] ;
}
}
} ( ) ;
RED . app . get ( "/serialports" , function ( req , res ) {
serialp . list ( function ( err , ports ) {
res . writeHead ( 200 , { 'Content-Type' : 'text/plain' } ) ;
res . write ( JSON . stringify ( ports ) ) ;
res . end ( ) ;
} ) ;
} ) ;