Skip to content

Commit

Permalink
Add payload version checking of the payload through the fPort.
Browse files Browse the repository at this point in the history
  • Loading branch information
RichardKroesen committed Mar 20, 2024
1 parent e0a0919 commit 0e23575
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 25 deletions.
117 changes: 96 additions & 21 deletions decoder_cayenneLPP_extreme.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@
* Copyright (c) 2024 March by Klaasjan Wagenaar, Tristan Bosveld and Richard Kroesen
*/

/**
* @brief Definitions for sensor types used in IoT device data decoding.
*
* This file contains the `SensorTypes` constant, which is a mapping of various sensor types
* to their respective characteristics. Each sensor type is an object with the following properties:
* - `type`: Numeric identifier for the sensor type.
* - `precision`: The factor by which the raw sensor data is divided to obtain a meaningful value.
* - `signed`: Boolean indicating if the sensor data is signed (true) or unsigned (false).
* - `bytes`: The number of bytes that represent the sensor's data in the transmission.
*/
const SensorTypes = {
DIG_IN: { type: 0, precision: 1, signed: false, bytes: 1 },
DIG_OUT: { type: 1, precision: 1, signed: false, bytes: 1 },
Expand All @@ -21,37 +31,106 @@ const SensorTypes = {
GPS_LOC: { type: 136, precision: 10000, signed: true, bytes: 12 }
};

/**
* @SensorTypes Reference Table:
*
* | Sensor Name | LPP | IPSO | Decimal Precision | Signed | Size Bytes |
* |-------------|------|--------|--------------------|--------|--------------|
* | DIG_IN | 0 | 3200 | 1 | false | 1 |
* | DIG_OUT | 1 | 3201 | 1 | false | 1 |
* | ANL_IN | 2 | 3202 | 100 | true | 2 |
* | ANL_OUT | 3 | 3203 | 100 | true | 2 |
* | ILLUM_SENS | 101 | 3301 | 1 | false | 2 |
* | PRSNC_SENS | 102 | 3302 | 1 | false | 1 |
* | TEMP_SENS | 103 | 3303 | 10 | true | 2 |
* | HUM_SENS | 104 | 3304 | 10 | false | 2 |
* | ACCRM_SENS | 113 | 3313 | 1000 | true | 6 |
* | BARO_SENS | 115 | 3315 | 10 | false | 2 |
* | GYRO_SENS | 134 | 3334 | 100 | true | 6 |
* | GPS_LOC | 136 | 3336 | 10000 | true | 12 |
*/

/**
* @brief Decodes the uplink data payload based on the specified payload version.
*
* This function decodes the input payload by examining the payload version. For encoding version 1.
*
* @param input A structure containing the payload to be decoded.
* @return Returns an object containing the decoded data, the version of the coding used,
* and arrays for warnings and errors. The returned object has the following structure:
* {
* decoder_version: <version>, // Integer representing the payload version
* data: <decoded_data>, // Object containing the decoded payload
* warnings: <warnings_array>, // Array of strings representing any warnings
* errors: <errors_array>, // Array of strings representing any errors encountered
* }
*/
function decodeUplink(input) {
let bytes = input.bytes;
let payload_version = input.fPort;
let decoded = {};


if (payload_version == 1) {
decoded = processPayloadVersion_ONE(bytes, decoded);
} else {
decoded.errors = ["Payload Version not supported: " + payload_version];
}

return {
decoder_version: payload_version,
data: decoded,
warnings: [],
errors: [],
};
}

/**
* @brief Decodes a value from a byte array based on the specified parameters.
*
* This function extracts a value starting from index `i` in the `bytes` array, interpreting
* a sequence of `byteLength` bytes according to whether the value is signed or unsigned,
* and then adjusting it by a given `precision`.
*
* @param bytes The array of bytes from which the value is to be extracted.
* @param i The starting index in the `bytes` array from which to begin decoding the value.
* @param isSigned A boolean indicating whether the value to be decoded is signed (true) or unsigned (false).
* @param precision The factor by which the raw decoded value should be divided to obtain the final value.
* This allows for the representation of fractional values without using floating point numbers
* in the encoded data.
* @param byteLength The number of bytes that make up the value to be decoded.
*
* @return An object containing two properties: `value` and `index`. `value` is the decoded number adjusted
* by the `precision`, and `index` is the new index in the `bytes` array after decoding the value,
* which can be used for subsequent decoding operations.
*/
function decodeValue(bytes, i, isSigned, precision, byteLength) {
let value = 0;
for (let byteIndex = byteLength - 1; byteIndex >= 0; byteIndex--) {
value = (value << 8) | bytes[i+byteIndex];
}

i += byteLength;

if (isSigned && (value & (1 << (8 * byteLength - 1)))) {

value = value - (1 << (8 * byteLength));
}
return { value: value / precision, index: i };
}

/**
* @brief Decodes downlink data from a byte array based on predefined sensor types.
*
* This function iterates through a given array of bytes, decoding each segment according to the
* sensor type and channel specified. It utilizes a nested `decodeValue` function to handle the
* conversion of byte segments into their corresponding sensor values, considering the signedness,
* precision, and byte length for each sensor type.
*
* @param input Object with a 'bytes' array of encoded sensor data. Each segment includes a sensor type
* identifier, channel number, and data bytes.
*
* @return Object with 'data', 'warnings', and 'errors'. 'Data' maps sensor readings to keys based on sensor
* type and channel. 'Warnings' and 'errors' are arrays with respective messages encountered during decoding.
* @brief Processes and decodes payload version 1.
*
* This function iterates through the bytes of the payload, decoding each segment according to the sensor type
* it represents. The decoded values are then added to the `decoded` object with keys
* representing the sensor type and channel.
*
* @param bytes An array of bytes representing the payload to be decoded.
* @param decoded An initially empty object that will be populated with the decoded sensor values.
* @return Returns the `decoded` object populated with keys and values representing the decoded sensor data.
*
*/
function decodeUplink(input) {
let bytes = input.bytes;
let decoded = {};
function processPayloadVersion_ONE(bytes, decoded) {
for (let i = 0; i < bytes.length;) {
let type = bytes[i++];
let channel = bytes[i++];
Expand Down Expand Up @@ -157,11 +236,7 @@ function decodeUplink(input) {
break;
}
}
return {
data: decoded,
warnings: [],
errors: []
};
return decoded;
}

module.exports = { SensorTypes, decodeUplink };
25 changes: 25 additions & 0 deletions downlinkCode.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ describe('decodeDownlink', () => {
/* TEST #1 for DIG_IN */
it('correctly decodes DIG_IN sensor data', () => {
const input = {
fPort: 1,
bytes: [
SensorTypes.DIG_IN.type,
5, // Channel
0 // Data (digital low)
]
};
const expected = {
decoder_version: 1,
data: {
digital_5: 0
},
Expand All @@ -35,13 +37,15 @@ describe('decodeDownlink', () => {
/* TEST #2 for DIG_OUT */
it('correctly decodes DIG_OUT sensor data', () => {
const input = {
fPort: 1,
bytes: [
SensorTypes.DIG_OUT.type, // Assuming SensorTypes is structured as shown previously
2, // Channel
1 // Data (digital high)
]
};
const expected = {
decoder_version: 1,
data: {
digital_2: 1
},
Expand All @@ -57,6 +61,7 @@ describe('decodeDownlink', () => {
/* TEST #3 */
it('correctly decodes ANL_IN sensor data', () => {
const input = {
fPort: 1,
bytes: [
SensorTypes.ANL_IN.type,
1, // Channel
Expand All @@ -66,6 +71,7 @@ describe('decodeDownlink', () => {
]
};
const expected = {
decoder_version: 1,
data: {
analog_1: 2.68
},
Expand All @@ -81,6 +87,7 @@ describe('decodeDownlink', () => {
/* TEST #4 Negative Values */
it('correctly decodes ANL_IN sensor negative data', () => {
const input = {
fPort: 1,
bytes: [
SensorTypes.ANL_IN.type,
1, // Channel
Expand All @@ -90,6 +97,7 @@ describe('decodeDownlink', () => {
]
};
const expected = {
decoder_version: 1,
data: {
analog_1: -0.12
},
Expand All @@ -105,6 +113,7 @@ describe('decodeDownlink', () => {
/* Test #5 for ILLUM_SENS sensor data */
it('correctly decodes ILLUM_SENS sensor data', () => {
const input = {
fPort: 1,
bytes: [
SensorTypes.ILLUM_SENS.type,
1, // Channel
Expand All @@ -113,6 +122,7 @@ describe('decodeDownlink', () => {
]
};
const expected = {
decoder_version: 1,
data: {
illumination_1: 100
},
Expand All @@ -128,13 +138,15 @@ describe('decodeDownlink', () => {
/* Test #6 for PRSNC_SENS sensor data */
it('correctly decodes PRSNC_SENS sensor data', () => {
const input = {
fPort: 1,
bytes: [
SensorTypes.PRSNC_SENS.type,
2, // Channel
1 // Presence detected
]
};
const expected = {
decoder_version: 1,
data: {
presence_2: 1
},
Expand All @@ -150,6 +162,7 @@ describe('decodeDownlink', () => {
/* Test #7 for TEMP_SENS sensor data (negative value) */
it('correctly decodes TEMP_SENS sensor negative data', () => {
const input = {
fPort: 1,
bytes: [
SensorTypes.TEMP_SENS.type,
3, // Channel
Expand All @@ -158,7 +171,9 @@ describe('decodeDownlink', () => {
]
};
const expectedValue = -1.2;

const expected = {
decoder_version: 1,
data: {
temperature_3: expectedValue
},
Expand All @@ -174,13 +189,15 @@ describe('decodeDownlink', () => {
/* Test #8 for HUM_SENS sensor data */
it('correctly decodes HUM_SENS sensor data', () => {
const input = {
fPort: 1,
bytes: [
SensorTypes.HUM_SENS.type,
1, // Channel
50
]
};
const expected = {
decoder_version: 1,
data: {
humidity_1: 5.0
},
Expand All @@ -196,6 +213,7 @@ describe('decodeDownlink', () => {
/* Test #9 for ACCRM_SENS sensor data */
it('correctly decodes ACCRM_SENS sensor data', () => {
const input = {
fPort: 1,
bytes: [
SensorTypes.ACCRM_SENS.type,
1, // Channel
Expand All @@ -206,6 +224,7 @@ describe('decodeDownlink', () => {
]
};
const expected = {
decoder_version: 1,
data: {
accelerometer_1: {
x: 1 / SensorTypes.ACCRM_SENS.precision,
Expand All @@ -225,6 +244,7 @@ describe('decodeDownlink', () => {
/* Test #10 for BARO_SENS sensor data */
it('correctly decodes BARO_SENS sensor data', () => {
const input = {
fPort: 1,
bytes: [
SensorTypes.BARO_SENS.type,
1, // Channel
Expand All @@ -233,6 +253,7 @@ describe('decodeDownlink', () => {
]
};
const expected = {
decoder_version: 1,
data: {
barometer_1: ((1 << 8) + 144) / SensorTypes.BARO_SENS.precision // Assuming 0.1 hPa precision
},
Expand All @@ -248,6 +269,7 @@ describe('decodeDownlink', () => {
/* Test #11 for GYRO_SENS sensor data */
it('correctly decodes GYRO_SENS sensor data', () => {
const input = {
fPort: 1,
bytes: [
SensorTypes.GYRO_SENS.type,
1, // Channel
Expand All @@ -258,6 +280,7 @@ describe('decodeDownlink', () => {
]
};
const expected = {
decoder_version: 1,
data: {
gyroscope_1: {
x: 100 / SensorTypes.GYRO_SENS.precision,
Expand Down Expand Up @@ -289,6 +312,7 @@ describe('decodeDownlink', () => {
const LAT_LON_PRECISION = 10000;
const ALTITUDE_PRECISION = 100;
const input = {
fPort: 1,
bytes: [
SensorTypes.GPS_LOC.type,
6,
Expand All @@ -299,6 +323,7 @@ describe('decodeDownlink', () => {
};

const expected = {
decoder_version: 1,
data: {
gps_6: { // Assuming channel 6 for GPS
x: 515074/LAT_LON_PRECISION, // Latitude
Expand Down
4 changes: 4 additions & 0 deletions downlinkCode_integration.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ describe('Decode Downlink with Multiple Sensor Types', () => {
}

const input = {
fPort: 1,
bytes: [
SensorTypes.DIG_IN.type, 1, 1, // DIG_IN, channel 1, value 1 (digital input ON)
SensorTypes.TEMP_SENS.type, 2, 0x2C, 0x01, // TEMP_SENS, channel 2, value 300 (30.0°C after division)
Expand All @@ -31,6 +32,7 @@ describe('Decode Downlink with Multiple Sensor Types', () => {
};

const expected = {
decoder_version: 1,
data: {
digital_1: 1, // Digital input ON
temperature_2: 30.0, // 30.0°C
Expand Down Expand Up @@ -60,6 +62,7 @@ describe('Decode Downlink with Multiple Sensor Types', () => {
}

const input = {
fPort: 1,
bytes: [
SensorTypes.DIG_IN.type, 1, 1, // DIG_IN, channel 1, value 1 (digital input ON)
SensorTypes.TEMP_SENS.type, 2, 0x2C,0x01, // TEMP_SENS, channel 2, value 300 (30.0°C after division)
Expand All @@ -73,6 +76,7 @@ describe('Decode Downlink with Multiple Sensor Types', () => {

// Adjusting expectations to include errors
const expected = {
decoder_version: 1,
data: {
"digital_1": 1,
errors: ["Unknown type: 200"],
Expand Down
4 changes: 0 additions & 4 deletions samples.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,6 @@
}






// 6700FA00680173046502B4007104FAFFFCFFE80302054901
// 0x67,0x00,0xFA,0x00,
// 0x68,0x01,0x73,0x04,
Expand Down

0 comments on commit 0e23575

Please sign in to comment.