22
33const baEnum = require ( './enum' ) ;
44
5- module . exports . encode = ( buffer , func , msgLength ) => {
5+ const DefaultBACnetPort = 47808 ;
6+
7+ module . exports . encode = ( buffer , func , msgLength , originatingIP ) => {
68 buffer [ 0 ] = baEnum . BVLL_TYPE_BACNET_IP ;
79 buffer [ 1 ] = func ;
810 buffer [ 2 ] = ( msgLength & 0xFF00 ) >> 8 ;
911 buffer [ 3 ] = ( msgLength & 0x00FF ) >> 0 ;
12+ if ( originatingIP ) {
13+ // This is always a FORWARDED_NPDU regardless of the 'func' parameter.
14+ if ( func !== baEnum . BvlcResultPurpose . FORWARDED_NPDU ) {
15+ throw new Error ( 'Cannot specify originatingIP unless '
16+ + 'BvlcResultPurpose.FORWARDED_NPDU is used.' ) ;
17+ }
18+ // Encode the IP address and optional port into bytes.
19+ const [ ipstr , portstr ] = originatingIP . split ( ':' ) ;
20+ const port = parseInt ( portstr ) || DefaultBACnetPort ;
21+ const ip = ipstr . split ( '.' ) ;
22+ buffer [ 4 ] = parseInt ( ip [ 0 ] ) ;
23+ buffer [ 5 ] = parseInt ( ip [ 1 ] ) ;
24+ buffer [ 6 ] = parseInt ( ip [ 2 ] ) ;
25+ buffer [ 7 ] = parseInt ( ip [ 3 ] ) ;
26+ buffer [ 8 ] = ( port & 0xFF00 ) >> 8 ;
27+ buffer [ 9 ] = ( port & 0x00FF ) >> 0 ;
28+ return 6 + baEnum . BVLC_HEADER_LENGTH ;
29+ } else {
30+ if ( func === baEnum . BvlcResultPurpose . FORWARDED_NPDU ) {
31+ throw new Error ( 'Must specify originatingIP if '
32+ + 'BvlcResultPurpose.FORWARDED_NPDU is used.' ) ;
33+ }
34+ }
1035 return baEnum . BVLC_HEADER_LENGTH ;
1136} ;
1237
@@ -15,31 +40,47 @@ module.exports.decode = (buffer, offset) => {
1540 const func = buffer [ 1 ] ;
1641 const msgLength = ( buffer [ 2 ] << 8 ) | ( buffer [ 3 ] << 0 ) ;
1742 if ( buffer [ 0 ] !== baEnum . BVLL_TYPE_BACNET_IP || buffer . length !== msgLength ) return ;
43+ let originatingIP = null ;
1844 switch ( func ) {
1945 case baEnum . BvlcResultPurpose . BVLC_RESULT :
2046 case baEnum . BvlcResultPurpose . ORIGINAL_UNICAST_NPDU :
2147 case baEnum . BvlcResultPurpose . ORIGINAL_BROADCAST_NPDU :
2248 case baEnum . BvlcResultPurpose . DISTRIBUTE_BROADCAST_TO_NETWORK :
23- len = 4 ;
24- break ;
25- case baEnum . BvlcResultPurpose . FORWARDED_NPDU :
26- len = 10 ;
27- break ;
2849 case baEnum . BvlcResultPurpose . REGISTER_FOREIGN_DEVICE :
2950 case baEnum . BvlcResultPurpose . READ_FOREIGN_DEVICE_TABLE :
3051 case baEnum . BvlcResultPurpose . DELETE_FOREIGN_DEVICE_TABLE_ENTRY :
3152 case baEnum . BvlcResultPurpose . READ_BROADCAST_DISTRIBUTION_TABLE :
3253 case baEnum . BvlcResultPurpose . WRITE_BROADCAST_DISTRIBUTION_TABLE :
3354 case baEnum . BvlcResultPurpose . READ_BROADCAST_DISTRIBUTION_TABLE_ACK :
3455 case baEnum . BvlcResultPurpose . READ_FOREIGN_DEVICE_TABLE_ACK :
56+ len = 4 ;
57+ break ;
58+ case baEnum . BvlcResultPurpose . FORWARDED_NPDU :
59+ // Work out where the packet originally came from before the BBMD
60+ // forwarded it to us, so we can tell the BBMD where to send any reply to.
61+ const port = ( buffer [ 8 ] << 8 ) | buffer [ 9 ] ;
62+ originatingIP = buffer . slice ( 4 , 8 ) . join ( '.' ) ;
63+
64+ // Only add the port if it's not the usual one.
65+ if ( port != DefaultBACnetPort ) {
66+ originatingIP += ':' + port ;
67+ }
68+
69+ len = 10 ;
70+ break ;
3571 case baEnum . BvlcResultPurpose . SECURE_BVLL :
72+ // unimplemented
3673 return ;
3774 default :
3875 return ;
3976 }
4077 return {
4178 len : len ,
4279 func : func ,
43- msgLength : msgLength
80+ msgLength : msgLength ,
81+ // Originating IP is set to the IP address of the node that originally
82+ // sent the packet, when it has been forwarded to us by a BBMD (since the
83+ // BBMD's IP address will be in the sender field.
84+ originatingIP : originatingIP ,
4485 } ;
4586} ;
0 commit comments