function padStart(s, len, padding) { if (s.length >= len) { return s; } var padding_length = len - s.length; var t = "" var i = 0; for (; i < padding_length; i++) { t += padding; } return t + s; } function Decoder() { this.pow = function (x , y) { var result = 1; var i = 0; var base = y < 0 ? 1/x : x; var e = y < 0 ? -y : y; for (i = 0; i < e; ++i) { result = result * base; } return result; } this.binary_parse_int = function (binary) { var _this = this; var i = 0; var result = 0; var b = 0; var arr = binary.split(""); arr.forEach(function (value, index, array) { b = value === '1' ? 1 : 0; result += b * _this.pow(2, array.length - index - 1) }) return result } this.parse_len = function (len) { this.parse_length += len; this.sensor_parse += len; } this.add_data = function (data) { this.data[this.sensor_cnt].sensor.push({ pk_id: this.data_id, data: data }) } this._decode_float = function ( exponent_len, fraction_len, offset ) { var _this = this; var len = (exponent_len + fraction_len + 1) / 8; this.parse_len(len) var binary = ""; for (i = 1; i < len + 1; ++i) { binary = binary + padStart(this.bytes[this.parse_length - i].toString(2), 8, "0"); } var sign = binary[0] === '0' ? 1 : -1; var exponent = this.binary_parse_int(binary.slice(1, exponent_len + 1)); var fraction = 0; binary.slice(exponent_len + 1).split("").forEach(function (value, index) { fraction += _this.pow(0.5, index + 1) * _this.binary_parse_int(value) }) if (exponent !== 0) { fraction += 1; } else { exponent = 1; } this.add_data( sign * this.pow(2, exponent - offset) * fraction); }; this.decode_float = function () { this._decode_float(8, 23, 127); }; this.decode_double = function () { this._decode_float(11, 52, 1023); }; this.decode_array = function () { this.parse_len(1); var length = this.bytes[this.parse_length - 1]; this.parse_len(length); this.add_data(this.bytes.slice(this.parse_length - length, this.parse_length)); }; this.decode_bool = function () { this.parse_len(1) var flag = this.bytes[this.parse_length - 1]; this.add_data( !!flag); }; this.decode_int8 = function () { this.parse_len(1); var byte = this.bytes[this.parse_length - 1]; var sign = byte > 127 ? -1 : 1; var i = (byte & 0x7f); if (sign === -1) { i = (i ^ 0x7f) + 1; } this.add_data( sign * i); }; this.decode_uint8 = function () { this.parse_len(1); var byte = this.bytes[this.parse_length - 1]; this.add_data(byte); }; this.decode_int16 = function () { this.parse_len(2); var low = this.bytes[this.parse_length - 2]; var high = this.bytes[this.parse_length - 1]; var sign = high > 127 ? -1 : 1; var i = (((high & 0x7f) << 8) | low); if (sign === -1) { i = (i ^ 0x7fff) + 1; } this.add_data(sign * i); }; this.decode_uint16 = function () { this.parse_len(2); var low = this.bytes[this.parse_length - 2]; var high = this.bytes[this.parse_length - 1]; this.add_data(((high << 8) | low)); }; this.decode_int32 = function () { this.parse_len(4); var b1 = this.bytes[this.parse_length - 4]; var b2 = this.bytes[this.parse_length - 3]; var b3 = this.bytes[this.parse_length - 2]; var b4 = this.bytes[this.parse_length - 1]; var sign = b4 > 127 ? -1 : 1; var i =(((b4 & 0x7f) << 24) | (b3 << 16) | (b2 << 8) | b1); if (sign === -1) { i = (i ^ 0x7fffffff) + 1; } this.add_data(sign * i); }; this.decode_uint32 = function () { this.parse_len(4); var b1 = this.bytes[this.parse_length - 4]; var b2 = this.bytes[this.parse_length - 3]; var b3 = this.bytes[this.parse_length - 2]; var b4 = this.bytes[this.parse_length - 1]; this.add_data(((b4 << 24) | (b3 << 16) | (b2 << 8) | b1) >>> 0); }; this.sensor_decode = function () { this.parse_len(1); if (this.data_length <= this.parse_length) { throw TypeError("data length: " + this.data_length + " exceed") } var data_id = this.bytes[this.parse_length - 1] >> 4; var data_type = this.bytes[this.parse_length - 1] & 0x0f; this.data_id = data_id; switch (data_type) { case 0: this.decode_array(); break; case 1: this.decode_double(); break; case 2: this.decode_float(); break; case 3: this.decode_bool(); break; case 4: this.decode_int8(); break; case 5: this.decode_uint8(); break; case 6: this.decode_int16(); break; case 7: this.decode_uint16(); break; case 8: this.decode_int32(); break; case 9: this.decode_uint32(); break; default: throw TypeError("Nonsupport data format"); } if (this.sensor_parse > this.sensor_length) { throw RangeError("Sensor Data Format Error, sensor data length " + this.sensor_length) } if (this.sensor_parse < this.sensor_length) { this.data_cnt++; this.sensor_decode() } } this._decode = function () { this.parse_length += 3; this.data_cnt = 0; var sensor_id = this.bytes[this.parse_length - 3] + (this.bytes[this.parse_length - 2] << 8) this.sensor_length = this.bytes[this.parse_length - 1]; this.sensor_parse = 0; this.data.push({ sensor_id: sensor_id, sensor: [] }); if(this.sensor_length ===0) { this.data[this.sensor_cnt].sensor.push("Sensor data reading failed."); } else { this.sensor_decode(); } if (this.parse_length < this.data_length) { this.sensor_cnt++; this._decode() } } this.decode = function (bytes) { this.bytes = bytes; this.parse_length = 0; this.sensor_cnt = 0; this.data_length = bytes.length; this.data = []; this._decode(); if (this.data_length !== this.parse_length) { throw Error("data format error") } return this.data } return this; } function Decode(fPort, bytes) { var decoder = Decoder(); return { data:{ data: decoder.decode(bytes) } }; // return {"temperature": 22.5}; }