Payload Format / Decode for TM-901 / N1C2 sensor from KCS TraceME

We cannot tell. What’s the source of your quoted explanation above? Where did you find the indexes such as bytes[19]? (For future readers, please also provide the device brand and type.)

If the quote is taken from documentation for your sensor, and if you’ve got the byte indexes correct, and if the values are sent MSB first, and if the values are sent as signed integer numbers, and if they don’t need to be divided by some factor to get decimal numbers, then: yes. But we cannot tell from the information you’re providing.

Looking at the example payload (for which we still don’t know the expected values either!), it seems that byte[19] is (hexadecimal) 0xFF, and so is byte[20]. (Beware that JavaScript starts counting from zero, not from one, just like many programming languages do as well.) That’s probably not a valid reading for compass_x?

It’s crucial you understand the shifting. Let’s decipher the next two bytes, those for compass_y: FD and 09, when displayed in the human readable hexadecimal notation. In binary notation, those are the bit sequences 11111101 and 00001001.

  • A left shift of 8 bits in 11111101 << 8 yields 11111101 00000000 (or, as it’s actually always 32 bits in JavaScript: 00000000 00000000 11111101 00000000).
  • Next, a bitwise OR in 11111101 00000000 | 00001001 yields 11111101 00001001.

Please follow the links above and read the documentation.

As we’re shifting 8 bits (which is a full byte) at a time, the above is much easier to read in hexadecimal:

  • For the byte FD, the shifting FD << 8 yields 00 00 FD 00.
  • Next, 00 00 FD 00 | 09 yields 00 00 FD 09.

When doing bitwise operations, JavaScript will interpret its operands as 32-bits signed integers, so will interpret the above 00 00 FD 09 as a large positive number, 64.777. Instead, if it can indeed be negative, you’ll need the sign extension that I linked to above. That would result in:

Note that the above applies to bitwise operators in JavaScript, as used in a TTN Console payload format. Other programming languages are unlikely to always assume 32-bits signed integers for bitwise operators.

Now, applying the above to byte[19] and byte[20] one would get 0xFFFFFFFF for compass_x, which is exactly -1. That might be correct, but I cannot tell. Finally, for compass_z you would get 0x00000007 (here, no sign propagating applies).

Finally, even with the above shifting and sign extension, Math.atan2(0xFFFFFD09, 0xFFFFFFFF) * 180 / Math.Pi will still give you NaN, Not-a-Number. So, JavaScript cannot do that math given these values. Maybe those are edge cases, maybe the formula is wrong, maybe you’re looking at the wrong bytes.

If those are expected edge cases, then you could use the following to suppress the NaN which TTN does not like:

return {
  ...,
  heading: isNaN(heading) ? null : heading,
  ...
}

That’s the ternary operator already mentioned in Decrypting messages for dummies - #4 by arjanvanb as well.

In your case, the formula is wrong. Debugging will show that Math.atan2(-759, -1) * 180 yields -282.98 just fine. However, Math.Pi is undefined, and -282.98 / undefined is NaN. You’ll need the uppercase Math.PI instead. (And you still might want to check all of the above.)

Bonus, to limit the number of decimals, use:

// Unary plus operator to cast string result of toFixed to number
heading: isNaN(heading) ? null : +heading.toFixed(1)
2 Likes