node-red-contrib-kbr-ebus
Version:
KBR Gmbh - nodes for accessing ebus devices
196 lines (168 loc) • 6.61 kB
JavaScript
const ebus = {
//Ermittelt die Checksumme für ein eBus-Telex
calcEbusTelexCRC: (ebusTelexByteArray) => {
var crc=0;
ebusTelexByteArray.forEach(function(byteVal) {
crc ^= byteVal;
});
return crc;
},
//Erzeugt ein eBus-Telex als (byte)Buffer
createTelex:(fromAddress,toAddress,data)=>{
data=Buffer.from(data);
var lot=(5+data.length) & 0xFF;
var buffer=Buffer.alloc(lot+2);
var pos=0;
buffer.writeUInt8(0x02,pos++);
buffer.writeUInt8(lot,pos++);
buffer.writeUInt16BE(toAddress,pos);
pos+=2;
buffer.writeUInt16BE(fromAddress,pos);
pos+=2;
data.copy(buffer,pos,0,data.length);
pos+=data.length;
var telexWithoutCRC=buffer.slice(0,buffer.length-1);
var crc = ebus.calcEbusTelexCRC(telexWithoutCRC);
buffer.writeUInt8(crc,pos);
return buffer;
},
EbusTelexSOT:{
NONE:0,
STX:2,
ACK:6,
NAK:0x15,
CAN:0x18,
WAIT:0xE1
},
//Ermittelt aus einem byte-Array das nächste Telex, oder eine Ein-Byte-Telex-Antwort
//Liefert
detectEbusTelexFromBuffer:(telexbuffer)=>{
//console.log("Eval",telexbuffer);
if(!Buffer.isBuffer(telexbuffer) || telexbuffer.length===0)
return null;
var telex={
id:new Date(),
stx:ebus.EbusTelexSOT.NONE,
lot:0,
to:0,
from:0,
data:null,
error:null,
bufferBefore:Buffer.allocUnsafe(0),
bufferAfter:Buffer.allocUnsafe(0),
raw:Buffer.allocUnsafe(0),
getClassid:()=>{
}
};
var pos=0;
if(Buffer.isBuffer(telexbuffer) && telexbuffer.length>0){
var bufferBefore=[];
//First byte
var currentTelexByte=telexbuffer.readUInt8(0);
var isAnswer=false;
do{
switch(currentTelexByte){
case ebus.EbusTelexSOT.STX:
case ebus.EbusTelexSOT.ACK:
case ebus.EbusTelexSOT.NAK:
case ebus.EbusTelexSOT.CAN:
case ebus.EbusTelexSOT.WAIT:
isAnswer=true;
break;
}
if(isAnswer){
break;
}
else{
bufferBefore.push(currentTelexByte);
telexbuffer=telexbuffer.slice(1,telexbuffer.length);
}
if(telexbuffer.length===0)
break;
//Next byte
currentTelexByte=telexbuffer.readUInt8(0);
}while(!isAnswer);
telex.bufferBefore=Buffer.from(bufferBefore);
if(!isAnswer)
return null;
telex.stx=currentTelexByte;
//Check if this is a valid telex start
if(telex.stx===ebus.EbusTelexSOT.STX){
//Ensure 8 bytes minimum length of a telex
if(telexbuffer.length<8)
return null;
pos=1;
//Get telex length
telex.lot=telexbuffer[pos++];
//Ensure that all bytes of telex are available
if((telexbuffer.length-2)<telex.lot){
return null;
}
//Verify checksum
var telexCrc=telexbuffer[telex.lot+1];
var allTelexBytesWithoutChecksum=telexbuffer.slice(0,telex.lot+1);
var checkCrc=ebus.calcEbusTelexCRC(allTelexBytesWithoutChecksum);
if(telexCrc!=checkCrc){
telex.bufferAfter=telexbuffer.slice(telex.lot+2);
telex.error="Telex checksum error";
return telex;
}
//Get telex content
telex.to=telexbuffer.readUInt16BE(pos);
pos+=2;
telex.from=telexbuffer.readUInt16BE(pos);
pos+=2;
telex.data=telexbuffer.slice(pos,telex.lot+1);
telex.raw=telexbuffer.slice(0,telex.lot+2);
telex.bufferAfter=telexbuffer.slice(telex.lot+2);
//console.log("TLX OK",telex);
return telex;
}
else{
telex.raw=telexbuffer.slice(0,1);
telex.bufferAfter=telexbuffer.slice(1);
//console.log("TLX OK",telex);
return telex;
}
}
return null;
},
TelexDetector:function(){
var _globalBuffer=Buffer.from([]);
return{
_debugLog:false,
log:function(...args){
if(this._debugLog)
console.log(...args);
},
getBuffer:function(){
return _globalBuffer;
},
clearBuffer:function(){
_globalBuffer=[];
this.log("Closing");
},
detect:function(data,callback,done){
if(!Buffer.isBuffer(data)){
this.log("Data is no buffer!");
return;
}
//Concat buffer data
var list=[];
list.push(_globalBuffer);
list.push(Buffer.from(data));
_globalBuffer=Buffer.concat(list);
var result=[];
var telex=ebus.detectEbusTelexFromBuffer(_globalBuffer);
while(telex!==null){
this.log("Telex detected",telex);
if(callback) callback(telex);
_globalBuffer=Buffer.from(telex.bufferAfter);
telex=ebus.detectEbusTelexFromBuffer(_globalBuffer);
}
if(done) done();
}
}
}
}
module.exports = ebus;