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 .
* * /
2013-11-14 16:44:54 +01:00
var RED = require ( process . env . NODE _RED _HOME + "/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 ;
2013-12-06 22:03:33 +01:00
this . addchar = n . addchar || "false" ;
2013-09-05 16:02:48 +02:00
}
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 ;
2013-12-08 17:59:36 +01:00
node . port = serialPool . get ( this . serialConfig . serialport , this . serialConfig . serialbaud , this . serialConfig . newline ) ;
2013-12-06 22:03:33 +01:00
node . addCh = "" ;
if ( node . serialConfig . addchar == "true" ) { node . addCh = this . serialConfig . newline . replace ( "\\n" , "\n" ) . replace ( "\\r" , "\r" ) ; }
2013-09-25 16:18:55 +02:00
node . on ( "input" , function ( msg ) {
2013-12-06 22:03:33 +01:00
var payload = msg . payload ;
if ( typeof payload === "object" ) { payload = JSON . stringify ( payload ) ; }
if ( typeof payload !== "buffer" ) { payload = new String ( payload ) + node . addCh ; }
node . port . write ( payload , function ( err , res ) {
2013-12-08 17:59:36 +01:00
if ( err ) {
node . error ( err ) ;
}
2013-12-06 22:03:33 +01:00
} ) ;
2013-09-05 16:02:48 +02:00
} ) ;
} else {
this . error ( "missing serial config" ) ;
}
2013-12-06 22:03:33 +01:00
this . on ( "close" , function ( ) {
if ( this . serialConfig ) {
serialPool . close ( this . serialConfig . serialport ) ;
}
} ) ;
2013-09-05 16:02:48 +02:00
}
RED . nodes . registerType ( "serial out" , SerialOutNode ) ;
2013-11-03 20:09:45 +01:00
2013-09-05 16:02:48 +02:00
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 ;
2013-12-08 17:59:36 +01:00
this . port = serialPool . get ( this . serialConfig . serialport , this . serialConfig . serialbaud , this . serialConfig . newline ) ;
2013-09-05 16:02:48 +02:00
this . port . on ( 'data' , function ( msg ) {
2013-12-06 22:03:33 +01:00
node . send ( { "payload" : msg } ) ;
2013-09-05 16:02:48 +02:00
} ) ;
} else {
this . error ( "missing serial config" ) ;
}
2013-12-06 22:03:33 +01:00
this . on ( "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." ) ;
2013-09-05 16:02:48 +02:00
}
2013-12-06 22:03:33 +01:00
} ) ;
2013-09-05 16:02:48 +02:00
}
2013-12-06 22:03:33 +01:00
RED . nodes . registerType ( "serial in" , SerialInNode ) ;
2013-09-05 16:02:48 +02:00
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 ) ; } ,
2013-12-08 17:59:36 +01:00
close : function ( cb ) { this . serial . close ( cb ) ; } ,
write : function ( m , cb ) { this . serial . write ( m , cb ) ; } ,
2013-09-05 16:02:48 +02:00
}
newline = newline . replace ( "\\n" , "\n" ) . replace ( "\\r" , "\r" ) ;
var setupSerial = function ( ) {
2013-12-08 17:59:36 +01:00
if ( newline == "" ) {
obj . serial = new serialp . SerialPort ( port , {
baudrate : baud ,
parser : serialp . parsers . raw
} , true , function ( err , results ) { if ( err ) obj . serial . emit ( 'error' , err ) ; } ) ;
}
else {
obj . serial = new serialp . SerialPort ( port , {
baudrate : baud ,
parser : serialp . parsers . readline ( newline )
} , true , function ( err , results ) { if ( err ) obj . serial . emit ( 'error' , err ) ; } ) ;
}
obj . serial . on ( 'error' , function ( err ) {
util . log ( "[serial] serial port " + port + " error " + err ) ;
obj . tout = setTimeout ( function ( ) {
setupSerial ( ) ;
} , settings . serialReconnectTime ) ;
} ) ;
obj . serial . on ( 'close' , function ( ) {
if ( ! obj . _closing ) {
util . log ( "[serial] serial port " + port + " closed unexpectedly" ) ;
2013-12-06 22:03:33 +01:00
obj . tout = setTimeout ( function ( ) {
setupSerial ( ) ;
2013-12-08 17:59:36 +01:00
} , settings . serialReconnectTime ) ;
}
} ) ;
obj . serial . on ( 'open' , function ( ) {
util . log ( "[serial] serial port " + port + " opened at " + baud + " baud" ) ;
if ( obj . tout ) { clearTimeout ( obj . tout ) ; }
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 ) ) ;
2013-09-05 16:02:48 +02:00
}
2013-12-08 17:59:36 +01:00
}
else {
obj . _emitter . emit ( 'data' , d ) ;
}
} ) ;
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 ( ) {
2013-12-06 22:03:33 +01:00
util . log ( "[serial] serial port closed" ) ;
2013-09-05 16:02:48 +02:00
} ) ;
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 ( ) ;
} ) ;
} ) ;