multiwii-msp
Version:
NodeJS MultiWii Serial Protocol to send or receive commands from MultiWii via TCP/IP
134 lines (118 loc) • 3.94 kB
JavaScript
/**
*
* Device format
* 0 - $
* 1 - M
* 2 - <!>
* 3 - payload length
* 4 - no
* 5 - code
* 6-length - payload
* 7+length+1 - crc
*
* @param {int} type - protocol type (request, response)
* @constructor
*/
function TcpProtocol(type) {
this._data = [];
this._type = type;
}
TcpProtocol.TYPE = {
REQUEST : 1,
RESPONSE: 2
};
/**
*
* @param {int} id - package identifier
* @param {int} code - package code
* @param {Buffer} data - package payload
* @param {boolean} [prior=false] - package has priority or not
* @returns {Buffer}
*/
TcpProtocol.prototype.serialize = function (id, code, data, prior) {
var i, length, crc, buffer;
length = data === undefined || data === null ? 0 : data.length;
buffer = new Buffer(8 + length);
buffer.writeUInt8(36, 0); // $
buffer.writeUInt8(77, 1); // M
if (this._type === TcpProtocol.TYPE.REQUEST) {
buffer.writeUInt8(60, 2); // <
} else {
buffer.writeUInt8(62, 2); // >
}
buffer.writeUInt8(length, 3);
buffer.writeUInt8(id, 4);
buffer.writeUInt8(code, 5);
buffer.writeUInt8(prior ? 1 : 0, 6);
crc = 0x00 ^ id ^ code ^ length ^ (prior ? 1 : 0);
for (i = 0; i < length; i = i + 1) {
crc ^= data.readUInt8(i);
buffer.writeUInt8(data.readUInt8(i), i + 7);
}
buffer.writeUInt8(crc, buffer.length - 1);
return buffer;
};
/**
* Buffer from attribute is stored in data array
* Method unserialize first valid package from data array
* The valid package bits or invalid bits are removed from data array
*
* @param {Buffer} [data]
* @returns {{valid: boolean}|{valid: boolean, id: int, code: int, length: int, prior: boolean, data: Buffer}}
*/
TcpProtocol.prototype.unserialize = function (data) {
var i, length, id, code, prior, crc, offset, valid, response;
if (data) {
for (i = 0; i < data.length; i = i + 1) {
this._data[this._data.length] = data.readUInt8(i);
}
}
valid = false;
offset = 0;
while (offset < this._data.length) {
if (this._data[offset] !== 36) {
offset = offset + 1;
} else if (this._data[offset + 1] !== 77) {
offset = offset + 2;
} else if (this._data[offset + 2] !== 62 && this._type === TcpProtocol.TYPE.REQUEST) {
offset = offset + 3;
} else if (this._data[offset + 2] !== 60 && this._type === TcpProtocol.TYPE.RESPONSE) {
offset = offset + 3;
} else if (this._data[offset + 3] <= this._data.length - offset - 7) {
length = this._data[offset + 3];
id = this._data[offset + 4];
code = this._data[offset + 5];
prior = this._data[offset + 6] === 1;
crc = 0x00 ^ id ^ code ^ length ^ (prior ? 1 : 0);
for (i = 0; i < length; i = i + 1) {
crc ^= this._data[offset + 7 + i];
}
if (crc !== this._data[offset + 7 + length]) {
offset = offset + 7 + length;
} else {
data = new Buffer(length);
for (i = 0; i < length; i = i + 1) {
data.writeUInt8(this._data[offset + 7 + i], i);
}
valid = true;
offset = offset + 7 + length + 1;
break;
}
} else {
break;
}
}
this._data = this._data.slice(offset);
response = {
valid: valid
};
if (valid) {
response.id = id;
response.code = code;
response.length = length;
response.data = data;
response.prior = prior;
}
return response;
};
module.exports = TcpProtocol;