Help a Poor Guy with this Payload

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.