Sensor
function PrintHex(bytes, offset, length) { var output = ""; for (var i = offset; i < offset + length; i++) { var s = bytes[i].toString(16); while (s.length < 2) s = "0" + s; if (output.length === 0) output = output + s; else output = output + s; } return output; } function MakeBitParser(bytes, offset, length) { return { bits: bytes.slice(offset, offset + length), offset: 0, bitLength: length * 8, U32LE: function U32LE(bits) { if (bits > 32) throw ("Invalid argument!"); if (this.offset + bits > this.bitLength) throw ("Read past end of data!"); var out = 0; var total = 0; while (bits > 0) { var byteNum = Math.floor(this.offset / 8); var discardLSbs = this.offset & 7; var avail = Math.min(8 - discardLSbs, bits); var extracted = (this.bits[byteNum] >>> discardLSbs); var masked = (extracted << (32 - avail)) >>> (32 - avail); out |= ((masked << total) >>> 0); total += avail; bits -= avail; this.offset += avail; } return out; }, S32LE: function S32LE(bits) { return (this.U32LE(bits) << (32 - bits)) >> (32 - bits); } }; } function decodeUplink(input) { var p = input.fPort; var b = MakeBitParser(input.bytes, 0, input.bytes.length); var d = {}; if (p === 1) { d._type = "hello"; d.fwMaj = b.U32LE(8); d.fwMin = b.U32LE(8); d.prodId = b.U32LE(8); d.hwRev = b.U32LE(8); d.resetPowerOn = (b.U32LE(1) !== 0); d.resetWatchdog = (b.U32LE(1) !== 0); d.resetExternal = (b.U32LE(1) !== 0); d.resetSoftware = (b.U32LE(1) !== 0); b.U32LE(4); d.watchdogReason = b.U32LE(16); d.initialBatV = Number((2.0 + 0.007 * b.U32LE(8)).toFixed(2)); d.lrHw = b.U32LE(8); d.lrMaj = b.U32LE(8); d.lrMin = b.U32LE(8); } else if (p === 2) { d._type = "downlink ack"; d.sequence = b.U32LE(7); d.accepted = (b.U32LE(1) !== 0); d.fwMaj = b.U32LE(8); d.fwMin = b.U32LE(8); d.prodId = b.U32LE(8); d.hwRev = b.U32LE(8); d.port = b.U32LE(8); d.lrHw = b.U32LE(8); d.lrMaj = b.U32LE(8); d.lrMin = b.U32LE(8); } else if (p === 3) { d._type = "stats"; d.initialBatV = Number((2.0 + 0.007 * b.U32LE(8)).toFixed(3)); d.BatVMax = Number((2.0 + 0.007 * b.U32LE(8)).toFixed(3)); d.wakeupsPerTrip = b.U32LE(8); d.tripCount = 32 * b.U32LE(14); d.uptimeWeeks = b.U32LE(10); d.mAhUsed = 2 * b.U32LE(10); d.percentLora = 100 / 64 * b.U32LE(6); d.percentGnss = 100 / 64 * b.U32LE(6); d.percentWifi = 100 / 64 * b.U32LE(6); d.percentSleep = 100 / 64 * b.U32LE(6); d.percentDisch = 100 / 64 * b.U32LE(6); d.percentOther = 100 - d.percentLora - d.percentGnss - d.percentWifi - d.percentSleep - d.percentDisch; } else if (p === 5) { d._type = "location"; wifiCount = b.U32LE(5); d.inTrip = (b.U32LE(1) !== 0); d.inactive = (b.U32LE(1) !== 0); b.U32LE(3); d.timeSet = (b.U32LE(1) !== 0); d.posSeq = b.U32LE(5); d.wifi = []; for (var i = 0; i < wifiCount; i++) { var rssi = b.bits[2 + i * 7 + 0]; if (rssi >= 128) rssi -= 256; var mac = PrintHex(b.bits, 2 + i * 7 + 1, 6); d.wifi[i] = { rssi: rssi, mac: mac }; } var navBytes = b.bits.slice(2 + wifiCount * 7); if (navBytes.length > 0) { d.nav = PrintHex(navBytes, 0, navBytes.length); } } else if (p == 89) { d._type = "connect"; d.id = PrintHex(b.bits, 0, 6); d.devReset = ((b.bits[6] & 1) !== 0); d.fcntReset = ((b.bits[6] & 2) !== 0); d.fwMaj = b.bits[7]; d.fwMin = b.bits[8]; d.prodId = b.bits[9]; d.hwRev = b.bits[10]; } else if (p == 90) { d._type = "mtu advice"; d.mtu0 = b.U32LE(6); d.mtu1 = b.U32LE(7); d.mtu2 = b.U32LE(7); d.mod1 = b.U32LE(4); d.mod2 = b.U32LE(4); d.mod3 = b.U32LE(4); d.seq = b.U32LE(16); } else if (p == 91) { d._type = "alm cookie req"; d.baseTime = b.U32LE(16); d.baseCrc = "0x" + b.U32LE(16).toString(16); d.codeMask = b.U32LE(8); d.compMask = b.U32LE(8); d.lrHw = b.U32LE(8); d.lrMaj = b.U32LE(8); d.lrMin = b.U32LE(8); } else if (p == 92) { d._type = "alm chunk req"; d.offset = b.U32LE(15); d.count = b.U32LE(13); d.cookie = b.U32LE(4); } else if ((p >= 101) && (p <= 116)) { d._type = "fragments"; d.frameId = p - 101 + 16 * b.U32LE(4); d.total = b.U32LE(5) + 1; d.offset = b.U32LE(7); d.data = PrintHex(b.bits, 2, b.bits.length - 2); if (d.offset == 0) { d.port = b.bits[7]; d.size = d.total * 9 - b.U32LE(4); } } else if (p == 202) { d._type = "time req"; if ((b.bits.length == 6) && (b.U32LE(8) == 0x01)) { d.gpsTime = b.U32LE(32); d.token = b.U32LE(4); d.ansReq = (b.U32LE(1) !== 0); } } else { return { warnings: ['unknown FPort'], }; } return { data: d, }; }
This codec is sourced from The Things Network. All rights belong to The Things Network.
This codec is licensed under the GNU General Public License v3 (GPL v3). Modifications, if any, are clearly marked. You are free to use, modify, and distribute the codec under the terms of GPL v3.