open-sml
Version:
Smart Message Language Implementation
141 lines (123 loc) • 4.61 kB
JavaScript
/*!
* OpenSML
* Copyright(c) 2014-2015 D. Spautz (d.spautz@web.de)
* MIT Licensed
*/
var SmlBuffer = require('./SmlBuffer');
var Constants = require('./Constants');
var SmlMessage = require('./SmlMessage');
var Crc16 = require("./SmlCRC");
function SmlFile(){
this.messages = [];
this.valid=undefined;
}
SmlFile.prototype.write = function write(){
var buffer = new SmlBuffer(Buffer.alloc(this.getSize()));
buffer.writeUInt32(0x1b1b1b1b);
buffer.writeUInt32(0x01010101);
var lastMessageTag=null;
for(var msg in this.messages){
this.messages[msg].write(buffer);
lastMessageTag=this.messages[msg].getMessageTag();
}
if(lastMessageTag == Constants.PUBLIC_CLOSE_RESPONSE || lastMessageTag == Constants.PUBLIC_CLOSE_REQUEST){
var counterAddedBytes=0;
while (buffer.offset%4!==0) {
buffer.writeUInt8(0);
counterAddedBytes++;
}
buffer.writeUInt32(0x1b1b1b1b);
buffer.writeUInt8(0x1a);
buffer.writeUInt8(counterAddedBytes);
//console.log("CALC FOR");
//console.log(buffer.buffer.slice(0, buffer.offset).toString('hex'));
var crc=Crc16.crc16CCITT(buffer.buffer.slice(0, buffer.offset));
//console.log("Calculated write CRC16="+crc.toString(16));
buffer.writeUInt16(crc);
buffer.finalize();
}
else {
buffer.finalize(8);
}
return buffer;
};
SmlFile.prototype.getSize = function getSize(){
var size = 8;
for(var msg in this.messages){
size += this.messages[msg].getSize();
}
size += 4-(size%4) + 4 + 1 + 3; // Filler to end up dividable by 4, end sequence (4), end of message (1), checksum (2+1)
//console.log("SmlFile. size: "+size);
return size;
};
SmlFile.prototype.addMessage = function addMessage(smlMessage){
this.messages.push(smlMessage);
};
SmlFile.prototype.getMessages = function getMessages(){
return this.messages;
};
SmlFile.prototype.toString = function toString(){
var str = "START SML-File\n";
for(var msg in this.messages){
var message = this.messages[msg];
if (typeof message.toString === "function") {
str += message.toString() + "\n";
}
else {
str += message + "\n";
}
}
str += "END SML-File\n";
return str;
};
SmlFile.prototype.parse = function parse(buffer){
var smlBuffer = new SmlBuffer(buffer);
if(buffer.readUInt32BE(0)==0x1b1b1b1b){
smlBuffer.setOffset(4);
}
if(buffer.readUInt32BE(4)==0x01010101){
smlBuffer.setOffset(8);
} else if(buffer.readUInt32BE(4)==0x02020202){
smlBuffer.setOffset(8);
}
do{
var message = SmlMessage.parse(smlBuffer);
this.addMessage(message);
smlBuffer.readUInt8(); // EndOfSMLMessage
if(message.getMessageTag() == Constants.PUBLIC_CLOSE_RESPONSE || message.getMessageTag() == Constants.PUBLIC_CLOSE_REQUEST){
var counterAddedBytes=0;
while (buffer.offset%4!==0 || buffer.length-smlBuffer.offset>8) {
smlBuffer.readUInt8(0);
counterAddedBytes++;
}
//console.log("read "+counterAddedBytes+" added bytes. Offset now="+smlBuffer.offset+" from "+buffer.length);
if(smlBuffer.getOffset() < buffer.length && smlBuffer.readUInt32() == 0x1b1b1b1b){
if(smlBuffer.readUInt8() == 0x1a){
var addedBytes=smlBuffer.readUInt8();
if (counterAddedBytes!=addedBytes) {
//console.log("Added bytes do not match: awaited="+addedBytes+" read="+counterAddedBytes);
}
var crcRead=smlBuffer.readUInt16();
var crcCalc=Crc16.crc16CCITT(buffer.slice(0, smlBuffer.offset-2));
//console.log("CRC16-Compare Msg="+crcRead.toString(16)+", Calculated="+crcCalc.toString(16));
if (crcRead == crcCalc){
this.valid = true;
}
else {
crcCalc=Crc16.crc16CCITTRotate(buffer.slice(0, smlBuffer.offset-2));
//console.log("CRC16-Compare-Rotated Msg="+crcRead.toString(16)+", Calculated="+crcCalc.toString(16));
if (crcRead == crcCalc){
this.valid = true;
} else {
// Workaround for Holley DTZ541 uses CRC-16/Kermit
crcCalc = Crc16.crc16Kermit(buffer.slice(0, smlBuffer.offset - 2));
this.valid = crcRead === crcCalc;
}
}
}
}
//console.log('CRC16-Check: '+this.valid);
}
} while(smlBuffer.getOffset() < buffer.length-12);
};
module.exports = SmlFile;