From 45b0bae9451b1d12fe6ea101d63fdc9c1df26c4c Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sun, 28 Jul 2019 17:12:46 +0200 Subject: [PATCH 1/3] Cleanup of packed payload encoder - Cleanup of write*int functions - Multiply pressure by 10 (decoder was already dividing by 10) - Fix undefined behavior on intToBytes function. --- include/payload.h | 3 ++- src/payload.cpp | 37 +++++++++++++++++++++---------------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/include/payload.h b/include/payload.h index 1a74e762..b41bb113 100644 --- a/include/payload.h +++ b/include/payload.h @@ -67,9 +67,10 @@ private: private: uint8_t *buffer; uint8_t cursor; - void intToBytes(uint8_t pos, int32_t i, uint8_t byteSize); + void uintToBytes(uint64_t i, uint8_t byteSize); void writeUptime(uint64_t unixtime); void writeLatLng(double latitude, double longitude); + void writeUint64(uint64_t i); void writeUint32(uint32_t i); void writeUint16(uint16_t i); void writeUint8(uint8_t i); diff --git a/src/payload.cpp b/src/payload.cpp index df879467..8afd0b3b 100644 --- a/src/payload.cpp +++ b/src/payload.cpp @@ -92,8 +92,8 @@ void PayloadConvert::addGPS(gpsStatus_t value) { buffer[cursor++] = value.satellites; buffer[cursor++] = highByte(value.hdop); buffer[cursor++] = lowByte(value.hdop); - buffer[cursor++] = highByte((value.altitude + 1000) * 4); - buffer[cursor++] = lowByte((value.altitude + 1000) * 4); + buffer[cursor++] = highByte(value.altitude); + buffer[cursor++] = lowByte(value.altitude); #endif } @@ -195,7 +195,7 @@ void PayloadConvert::addGPS(gpsStatus_t value) { writeLatLng(value.latitude, value.longitude); writeUint8(value.satellites); writeUint16(value.hdop); - writeUint16((value.altitude + 1000) * 4); + writeUint16(value.altitude); #endif } @@ -227,15 +227,19 @@ void PayloadConvert::addTime(time_t value) { writeUint32(time); } -void PayloadConvert::intToBytes(uint8_t pos, int32_t i, uint8_t byteSize) { +void PayloadConvert::uintToBytes(uint64_t value, uint8_t byteSize) { for (uint8_t x = 0; x < byteSize; x++) { - buffer[x + pos] = (byte)(i >> (x * 8)); + byte next = 0; + if (sizeof(value) > x) { + next = static_cast((value >> (x * 8)) & 0xFF); + } + buffer[cursor] = next; + ++cursor; } - cursor += byteSize; } void PayloadConvert::writeUptime(uint64_t uptime) { - intToBytes(cursor, uptime, 8); + writeUint64(uptime); } void PayloadConvert::writeVersion(char *version) { @@ -244,24 +248,25 @@ void PayloadConvert::writeVersion(char *version) { } void PayloadConvert::writeLatLng(double latitude, double longitude) { - intToBytes(cursor, latitude, 4); - intToBytes(cursor, longitude, 4); + // Tested to at least work with int32_t, which are processed correctly. + writeUint32(latitude); + writeUint32(longitude); } -void PayloadConvert::writeUint32(uint32_t i) { intToBytes(cursor, i, 4); } +void PayloadConvert::writeUint64(uint64_t i) { uintToBytes(i, 8); } -void PayloadConvert::writeUint16(uint16_t i) { intToBytes(cursor, i, 2); } +void PayloadConvert::writeUint32(uint32_t i) { uintToBytes(i, 4); } -void PayloadConvert::writeUint8(uint8_t i) { intToBytes(cursor, i, 1); } +void PayloadConvert::writeUint16(uint16_t i) { uintToBytes(i, 2); } + +void PayloadConvert::writeUint8(uint8_t i) { uintToBytes(i, 1); } void PayloadConvert::writeUFloat(float value) { - int16_t h = (int16_t)(value * 100); - intToBytes(cursor, h, 2); + writeUint16(value * 100); } void PayloadConvert::writePressure(float value) { - int16_t h = (int16_t)(value); - intToBytes(cursor, h, 2); + writeUint16(value * 10); } /** From 19ee712e517c5442b452e431355e9878fe84a34a Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sun, 28 Jul 2019 17:22:04 +0200 Subject: [PATCH 2/3] Remove increased altitude resolution from plain decoder --- src/TTN/plain_decoder.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TTN/plain_decoder.js b/src/TTN/plain_decoder.js index c6eba7b4..b7478b9c 100644 --- a/src/TTN/plain_decoder.js +++ b/src/TTN/plain_decoder.js @@ -20,7 +20,7 @@ function Decoder(bytes, port) { decoded.longitude = ((bytes[i++] << 24) | (bytes[i++] << 16) | (bytes[i++] << 8) | bytes[i++]); decoded.sats = bytes[i++]; decoded.hdop = (bytes[i++] << 8) | (bytes[i++]); - decoded.altitude = ((bytes[i++] << 8) | (bytes[i++])) / 4 - 1000; + decoded.altitude = ((bytes[i++] << 8) | (bytes[i++])); } } @@ -41,7 +41,7 @@ function Decoder(bytes, port) { decoded.longitude = ((bytes[i++] << 24) | (bytes[i++] << 16) | (bytes[i++] << 8) | bytes[i++]); decoded.sats = bytes[i++]; decoded.hdop = (bytes[i++] << 8) | (bytes[i++]); - decoded.altitude = ((bytes[i++] << 8) | (bytes[i++])) / 4 - 1000; + decoded.altitude = ((bytes[i++] << 8) | (bytes[i++])); } if (port === 5) { From a061e75a9e00cb68ce4cf5f90a6916f862796dcd Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Sun, 28 Jul 2019 17:25:24 +0200 Subject: [PATCH 3/3] Add signed int decode types to packed decoder RSSI is a negative value => signed int Altitude is signed hdop and ufloat values were ints divided by 100, so set resolution to 2 decimals. Removed some code duplication by calling uint/int decode functions --- src/TTN/packed_decoder.js | 106 ++++++++++++++++++++++++-------------- 1 file changed, 67 insertions(+), 39 deletions(-) diff --git a/src/TTN/packed_decoder.js b/src/TTN/packed_decoder.js index 4663b827..b5379f28 100644 --- a/src/TTN/packed_decoder.js +++ b/src/TTN/packed_decoder.js @@ -37,7 +37,7 @@ function Decoder(bytes, port) { if (port === 3) { // device config data - return decode(bytes, [uint8, uint8, uint16, uint8, uint8, uint8, uint8, bitmap1, bitmap2, version], ['lorasf', 'txpower', 'rssilimit', 'sendcycle', 'wifichancycle', 'blescantime', 'rgblum', 'flags', 'payloadmask', 'version']); + return decode(bytes, [uint8, uint8, int16, uint8, uint8, uint8, uint8, bitmap1, bitmap2, version], ['lorasf', 'txpower', 'rssilimit', 'sendcycle', 'wifichancycle', 'blescantime', 'rgblum', 'flags', 'payloadmask', 'version']); } if (port === 4) { @@ -52,7 +52,7 @@ function Decoder(bytes, port) { if (port === 6) { // beacon proximity alarm - return decode(bytes, [uint8, uint8], ['rssi', 'beacon']); + return decode(bytes, [int8, uint8], ['rssi', 'beacon']); } if (port === 7) { @@ -123,37 +123,72 @@ var uint32 = function (bytes) { }; uint32.BYTES = 4; -var latLng = function (bytes) { - if (bytes.length !== latLng.BYTES) { - throw new Error('Lat/Long must have exactly 4 bytes'); - } - return bytesToInt(bytes) / 1e6; -}; -latLng.BYTES = 4; - -var uptime = function (bytes) { - if (bytes.length !== uptime.BYTES) { - throw new Error('Uptime must have exactly 8 bytes'); +var uint64 = function (bytes) { + if (bytes.length !== uint64.BYTES) { + throw new Error('uint64 must have exactly 8 bytes'); } return bytesToInt(bytes); }; -uptime.BYTES = 8; +uint64.BYTES = 8; + +var int8 = function (bytes) { + if (bytes.length !== int8.BYTES) { + throw new Error('int8 must have exactly 1 byte'); + } + var value = +(bytesToInt(bytes)); + if (value > 127) { + value -= 256; + } + return value; +}; +int8.BYTES = 1; + +var int16 = function (bytes) { + if (bytes.length !== int16.BYTES) { + throw new Error('int16 must have exactly 2 bytes'); + } + var value = +(bytesToInt(bytes)); + if (value > 32767) { + value -= 65536; + } + return value; +}; +int16.BYTES = 2; + +var int32 = function (bytes) { + if (bytes.length !== int32.BYTES) { + throw new Error('int32 must have exactly 4 bytes'); + } + var value = +(bytesToInt(bytes)); + if (value > 2147483647) { + value -= 4294967296; + } + return value; +}; +int32.BYTES = 4; + +var latLng = function (bytes) { + return +(int32(bytes) / 1e6).toFixed(6); +}; +latLng.BYTES = int32.BYTES; + +var uptime = function (bytes) { + return uint64(bytes); +}; +uptime.BYTES = uint64.BYTES; var hdop = function (bytes) { - if (bytes.length !== hdop.BYTES) { - throw new Error('hdop must have exactly 2 bytes'); - } - return +(bytesToInt(bytes) / 100).toFixed(1); + return +(uint16(bytes) / 100).toFixed(2); }; -hdop.BYTES = 2; +hdop.BYTES = uint16.BYTES; var altitude = function (bytes) { - if (bytes.length !== altitude.BYTES) { - throw new Error('Altitude must have exactly 2 bytes'); - } - return +(alt / 4 - 1000).toFixed(1); + // Option to increase altitude resolution (also on encoder side) + // return +(int16(bytes) / 4 - 1000).toFixed(1); + return +(int16(bytes)); }; -altitude.BYTES = 2; +altitude.BYTES = int16.BYTES; + var float = function (bytes) { if (bytes.length !== float.BYTES) { @@ -176,29 +211,19 @@ var float = function (bytes) { if (isNegative) { t = -t; } - return +(t / 100).toFixed(1); + return +(t / 100).toFixed(2); }; float.BYTES = 2; var ufloat = function (bytes) { - if (bytes.length !== ufloat.BYTES) { - throw new Error('Ufloat must have exactly 2 bytes'); - } - - var h = bytesToInt(bytes); - return +(h / 100).toFixed(1); + return +(uint16(bytes) / 100).toFixed(2); }; -ufloat.BYTES = 2; +ufloat.BYTES = uint16.BYTES; var pressure = function (bytes) { - if (bytes.length !== pressure.BYTES) { - throw new Error('Pressure must have exactly 2 bytes'); - } - - var h = bytesToInt(bytes); - return +(h / 10).toFixed(1); + return +(uint16(bytes) / 10).toFixed(1); }; -pressure.BYTES = 2; +pressure.BYTES = uint16.BYTES; var bitmap1 = function (byte) { if (byte.length !== bitmap1.BYTES) { @@ -255,6 +280,9 @@ if (typeof module === 'object' && typeof module.exports !== 'undefined') { uint8: uint8, uint16: uint16, uint32: uint32, + int8: int8, + int16: int16, + int32: int32, uptime: uptime, float: float, ufloat: ufloat,