Help a Poor Guy with this Payload

I have some problem with the decoding function and my programming skills are not so advanced…

I have read some post about parsing Gps negative data, but it works only with 6 bytes payload, my sketch actually return after Hex conversion “873fe946b44d1e” and the payload from that topic doesn’t work.

Here’s the decoder function from Best practices when sending GPS location data:

function Decoder(b, port) {
  // Amsterdam: 52.373141, 4.892435 = 0xD3FD07 1CBF00
  // La Paz: -16.489689, -68.119294 = 0xE07BFD 189BF5
  // New York: 40.7127, -74.0059    = 0x573606 25B5F4
  // Sidney: -33.868820, 151.209296 = 0x00D5FA 9C1217

  // Sign-extend the 3rd and 6th bytes into a 4th and 8th byte:
  var lat = (b[0] + (b[1]<<8) + (b[2]<<16) + (b[2] & 0x80 ? 0xFF<<24 : 0)) / 10000;
  var lng = (b[3] + (b[4]<<8) + (b[5]<<16) + (b[5] & 0x80 ? 0xFF<<24 : 0)) / 10000;

  return {
    location: {
      lat: lat,
      lng: lng
    love: "TTN payload functions"

You’re showing 7 bytes in 873fe946b44d1e, which cannot be evenly divided into two numeric values. We’d need to know how the nodes encode the data to be able to decode that. Maybe it includes an altitude as well?

i use a sketch from internet who give me the coordinates in this format…

if ( gps.time.isUpdated() && gps.location.isUpdated() ) {
    if ( gps.time.minute() != lastMinute ) {
      lastMinute = gps.time.minute();
      long lat = gps.location.rawLat().deg * 1000000;
           lat += gps.location.rawLat().billionths / 1000;
           lat += 100000000;
      long lng = gps.location.rawLng().deg * 1000000;
           lng += gps.location.rawLng().billionths / 1000;
           lng += 100000000;

…and how it it being sent?


that’s it:

  String message = "mac tx uncnf 2 ";
  message += String(lat,HEX);
  message += String(lng,HEX);

Hmmm, apparently that does not give one the same length for each value, though it seems they try, by using the lat += 100000000. But even when they have the same length in decimal, it might not be the same length in hexadecimal.

Any idea what the original values are? (Roughly, if you don’t want to expose your location.)

I’m located in Rome, and that’s the result of the operation in the sketch…

It seems no leading zeroes are sent. Instead, 7 bytes are sent for two numbers, which is 3.5 bytes per number. That makes life harder than needed (and it might be easier to change the Arduino code instead), but it’s a good example so here goes :slight_smile:

0x873fe946b44d1e is actually 0x0873fe94 and 0x06b44d1e hexadecimal without the leading zeroes. That is 141819540 and 112479518 decimal, being 41.819540 and 12.479518 for the coordinates.

So, we need bitwise operators to shift the bytes into their right positions, and use bitwise ORs to combine them into two numbers:

byte    ----- shifted -----
0  87    8700000
1  3f      3f000                
2  e9        e90         
3  46          4    6000000
4  b4                b40000
5  4d                  4d00
6  1e                    1e
        --------   -------- OR
        0873fe94   06b44d1e

To split 0x46 we can right-shift byte[3] >> 4 to get 0x04, and do a bitwise AND on byte[3] & 0x0F to get 0x06.

Around Rome, the following TTN payload function works:

function Decoder(bytes, port) {

  // 7 bytes total, 3.5 bytes per number: 0x873fe9 46 b44d1e is actually
  // 0x0873fe94 and 0x06b44d1e, without leading zeroes

  var lat = ((bytes[0]<<20 | bytes[1]<<12 | bytes[2]<<4 | bytes[3]>>4) 
            - 100000000) / 1000000;

  var lng = (( (bytes[3]&0x0F)<<24 | bytes[4]<<16 | bytes[5]<<8 | bytes[6])
            - 100000000) / 1000000;

  return {
    location: {
      lat: lat,
      lng: lng

However, this won’t work for negative values.

The minimum longitude of -180.00 would be sent as -180,000,000 + 100,000,000 = -80,000,000, being 0xFB3B4C00 in 4 bytes. For that String(lng,HEX) will also return 4 bytes (instead of 3.5 bytes), simply as it would be a different value without the leading F.

To support negative values, it might seem you could add/subtract (at least) 180,000,000 instead of 100,000,000 in all formulas, in both the Arduino code and the payload function, to always send positive numbers. But then large positive values would become 4 bytes long, like +360,000,000 is 0x15752A00. Actually, even with the original code, for +180.00 you would send 280,000,000, which already needs 4 bytes as 0x10B07600. Also, .billionths is probably always positive, even if gps.location.rawLat().deg is negative…?

In short: it’s a nasty encoding, unsuitable for negative values, and even unusable for large positive values.

Thank you so much! it works!
i’ll try to study your function :slight_smile: