Skip to content

Instantly share code, notes, and snippets.

@guileen
Created June 2, 2015 04:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save guileen/121ffeb66fad521a851a to your computer and use it in GitHub Desktop.
Save guileen/121ffeb66fad521a851a to your computer and use it in GitHub Desktop.
/**
* @param {Socket} socket auto handle 'data' event, and emit 'packet' event.
* @param {Object} options options params
* options.headSize the size of header
* options.getBodySize function(headBuffer) return bodySize
*/
exports.autoParsePacket = function (socket, options) {
var headSize = options.headSize;
var getBodySize = options.getBodySize;
if(!headSize || headSize <= 0) {
throw new Error('headSize should be a positive integer');
}
if(!getBodySize) {
throw new Error('getBodySize function is required');
}
var STATE_HEAD = 0;
var STATE_BODY = 1;
var state = STATE_HEAD;
var headOffset = 0;
// init headBuffer, we can reuse it cause it is fixed size.
var headBuffer = new Buffer(headSize);
var packetSize = 0;
var packetOffset = 0;
var packetBuffer;
socket.on('data', function (data) {
// data reading offset
var offset = 0, end = data.length;
// not read to the end
while(offset < end) {
if(state == STATE_HEAD) {
offset = parseHead(data, offset);
} else if (state == STATE_BODY) {
offset = parseBody(data, offset);
}
}
});
// read headBuffer from data start from offset.
// if ready init packetBuffer by headBuffer.
function parseHead(data, offset) {
var headEnd = Math.min(data.length, offset + headSize - headOffset);
data.copy(headBuffer, headOffset, offset, headEnd);
headOffset += (headEnd - offset);
if(headOffset === headSize) {
packetSize = headSize + getBodySize(headBuffer);
packetBuffer = new Buffer(packetSize);
headBuffer.copy(packetBuffer);
packetOffset = headSize;
state = STATE_BODY;
}
return headEnd;
}
// read packetBuffer from data start from offset
// if ready read next packet head.
function parseBody(data, offset) {
var bodyEnd = Math.min(data.length, offset + packetSize - packetOffset);
data.copy(packetBuffer, packetOffset, offset, bodyEnd);
packetOffset += (bodyEnd - offset);
if(packetOffset == packetSize) {
socket.emit('packet', packetBuffer);
headOffset = 0;
packetOffset = 0;
packetSize = 0;
packetBuffer = null;
state = STATE_HEAD;
}
return bodyEnd;
}
}
exports.splitReport0x30 = function(packet) {
// 0 func_code
// 1 packet_length
// 2-5 nodeid
// 6 status
// a. 7-8 volt
// b. 7-10 in
// c. 11-14 out
// -2 -1 count
var packets = [];
var skip = 0;
while(skip < packet.length) {
var len = packet[skip + 1];
if(skip + len > packet.length) throw new Error('bad cmd0x30 packet');
packets.push(packet.slice(skip, skip += len));
}
return packets;
}
exports.crc16 = function (buffer, len) {
var crc = 0xffff;
for (var i = 0; i < len; i++) {
crc = ((crc ^ buffer[i]) & 0x00ff) + (crc & 0xff00);
for (var bit = 0; bit < 8; bit++) {
if ((crc & 0x0001) === 0x0000) {
crc >>= 1;
}
else {
crc >>= 1;
crc ^= 0xa001;
}
}
}
crc = ((crc & 0x00ff) << 8) + ((crc & 0xff00) >> 8);
return(crc);
}
exports.sendPacket = function (sock, packet) {
exports.makeCrcPacket(packet);
sock.write(packet);
}
/**
* 构造一个合法的数据包
*/
exports.makeCrcPacket = function (packet) {
var len = packet.length;
packet[0] = 0xaa;
packet.writeUInt16BE(packet.length - 4, 2);
var crc = exports.crc16(packet, len - 2);
packet.writeUInt16BE(crc, len - 2);
return packet;
}
/**
* 检验一个包是否合法
*/
exports.isValidPacket = function (packet) {
var len = packet.length;
return packet[0] == 0xaa && packet.readUInt16BE(len-2)=== exports.crc16(packet,len-2);
}
exports.replyId = function (sock, funcCode, id) {
var packet = new Buffer(10);
packet[1] = funcCode;
packet.writeUInt32BE(id, 4);
exports.sendPacket(sock, packet);
}
/**
* 分隔一个包
* @return {Array[Buffer]}
*/
exports.slicePacket = function(packet, sliceSize, offset) {
offset = offset || 0;
var end, len = packet.length;
var slices = [];
while(offset < packet.length) {
end = offset + sliceSize;
if(end > len) break;
slices.push(packet.slice(offset, end));
offset = end;
}
return slices;
}
exports.readNodeKey = function(buffer, offset) {
var key = buffer.readUInt32BE(offset);
var type = key % 100;
var id = (key - type) / 100;
return [key, id, type];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment