Skip to content

Commit

Permalink
Merge pull request #8 from waggle-sensor/add-sap-flow
Browse files Browse the repository at this point in the history
Add ict as vendor and sap flow meter device
  • Loading branch information
FranciscoLozCoding authored Sep 4, 2024
2 parents 4de6b53 + 636a7a4 commit feb47c9
Show file tree
Hide file tree
Showing 9 changed files with 468 additions and 0 deletions.
3 changes: 3 additions & 0 deletions vendor/ict-international/index.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
endDevices:
# Unique identifier of the end device (lowercase, alphanumeric with dashes, max 36 characters)
- sfm1x # look in sfm1x.yaml for the end device definition
20 changes: 20 additions & 0 deletions vendor/ict-international/sfm1x-profile-us915.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Whether the end device supports class B
supportsClassB: false
# Whether the end device supports class C
supportsClassC: false
# LoRaWAN MAC version: 1.0, 1.0.1, 1.0.2, 1.0.3, 1.0.4 or 1.1
macVersion: 1.0.2
# LoRaWAN Regional Parameters version. Values depend on the LoRaWAN version:
# 1.0: TS001-1.0
# 1.0.1: TS001-1.0.1
# 1.0.2: RP001-1.0.2 or RP001-1.0.2-RevB
# 1.0.3: RP001-1.0.3-RevA
# 1.0.4: RP002-1.0.0 or RP002-1.0.1
# 1.1: RP001-1.1-RevA or RP001-1.1-RevB
regionalParametersVersion: RP001-1.0.2
# Whether the end device supports join (OTAA) or not (ABP)
supportsJoin: true
# Maximum EIRP
maxEIRP: 16 #NOTE: don't know what is the actual value - FL
# Whether the end device supports 32-bit frame counters
supports32bitFCnt: true #NOTE: don't know what is the actual value - FL
11 changes: 11 additions & 0 deletions vendor/ict-international/sfm1x-r1-1-codec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Uplink decoder decodes binary data uplink into a JSON object (optional)
uplinkDecoder:
fileName: sfm1x-r1-1.js

# Downlink encoder encodes JSON object into a binary data downlink (optional)
downlinkEncoder:
fileName: sfm1x-r1-1.js

# Downlink decoder decodes the encoded downlink message (optional, must be symmetric with downlinkEncoder)
downlinkDecoder:
fileName: sfm1x-r1-1.js
184 changes: 184 additions & 0 deletions vendor/ict-international/sfm1x-r1-1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
/* SFM1x Reduced Packet Decoder Base to be used with lorawan listener plugin
Includes Base Diagnostic and Switchable Result Packet
*/

// Structure Type Define, "nested" or "flat"
var TYPE = 'nested';

/*Class Buffer
Purpose: A psuedo buffer class for accessing packet data,
allows for uniformity between decoder types
*/
function Buf(buf) {
this.pl = buf;
this.length = this.pl.length;
}
Buf.prototype.readUInt8 = function (ofs) {
return (this.pl[ofs] << 24) >>> 24;
};
Buf.prototype.readUInt16BE = function (ofs) {
return ((this.pl[ofs++] << 24) | (this.pl[ofs++] << 16)) >>> 16;
};
Buf.prototype.readUInt32BE = function (ofs) {
return ((this.pl[ofs++] << 24) | (this.pl[ofs++] << 16) | (this.pl[ofs++] << 8) | this.pl[ofs++]) >>> 0;
};
Buf.prototype.readUInt16LE = function (ofs) {
return ((this.pl[ofs + 1] << 24) | (this.pl[ofs--] << 16)) >>> 16;
};
Buf.prototype.readUInt32LE = function (ofs) {
return ((this.pl[ofs + 3] << 24) | (this.pl[ofs + 2] << 16) | (this.pl[ofs + 1] << 8) | this.pl[ofs]) >>> 0;
};
Buf.prototype.readInt8 = function (ofs) {
return (this.pl[ofs] << 24) >> 24;
};
Buf.prototype.readInt16BE = function (ofs) {
return ((this.pl[ofs++] << 24) | (this.pl[ofs++] << 16)) >> 16;
};
Buf.prototype.readInt32BE = function (ofs) {
return ((this.pl[ofs++] << 24) | (this.pl[ofs++] << 16) | (this.pl[ofs++] << 8) | this.pl[ofs++]) >> 0;
};
Buf.prototype.readInt16LE = function (ofs) {
return ((this.pl[ofs + 1] << 24) | (this.pl[ofs--] << 16)) >> 16;
};
Buf.prototype.readInt32LE = function (ofs) {
return ((this.pl[ofs + 3] << 24) | (this.pl[ofs + 2] << 16) | (this.pl[ofs + 1] << 8) | this.pl[ofs]) >> 0;
};
Buf.prototype.readFloatBE = function (ofs) {
return B2Fl(this.readUInt32BE(ofs));
};
Buf.prototype.readFloatLE = function (ofs) {
return B2Fl(this.readUInt32LE(ofs));
};
Buf.prototype.slice = function (s, e) {
return this.pl.slice(s, e);
};
Buf.prototype.length = function () {
return this.pl.length;
};

/*Function Bytes2Float32(bytes)
Purpose: Decodes an array of bytes(len 4(32 bit) into a float.
Args: bytes - an array of bytes, 4 bytes long
Returns: 32bit Float representation
*/
function B2Fl(b) {
var sign = b >> 31 ? -1 : 1;
var exp = ((b >> 23) & 0xff) - 127;
var sig = b & ~(-1 << 23);
if (exp == 128) return sign * (sig ? Number.NaN : Number.POSITIVE_INFINITY);
if (exp == -127) {
if (sig === 0) return sign * 0.0;
exp = -126;
sig /= 1 << 22;
} else sig = (sig | (1 << 23)) / (1 << 23);
return sign * sig * Math.pow(2, exp);
}

/*Function buildNested(a) - SAGE version
Purpose: Takes an array and parses them into a clean and succinct object of nested parameter sets
Args: a - An array of arrays containing Parameter Sets
Returns: An Object containing nested Parameter Sets
*/
function buildNested(a) {
var exc = ['main', 'diagnostic', 'downlink', 'device_info', 'unknown'];
var ret = [];
for (var el in a) {
var e = a[el];
var par = {};
par['name'] = e[0];
par['channelId'] = e[1];
par['value'] = e[2];
var e_length = e.length;
if (e_length > 3 && exc.indexOf(e[3]) < 0) par['source'] = e[3];
if (e_length > 4) par['unit'] = e[4];
if (e_length > 5) par['address'] = e[5];
ret.push(par);
}
return ret;
}

/*Function buildFlat(a)
Purpose: Takes an array and parses them into a clean and succinct object of flat parameters
Args: a - An array of arrays containing Parameter Sets
Returns: An Object containing nested Parameter Sets
*/
function buildFlat(a) {
var exc = ['main', 'diagnostic', 'downlink', 'device_info', 'unknown'];
var ret = {};
for (var el in a) {
var e = a[el];
var label = '';
if (e.length == 6) {
e[0] = e[0] + e[5] + '_';
}
if (e.length <= 4) {
label = exc.indexOf(e[3]) < 0 ? e[0] + e[1] : e[0];
} else {
label = exc.indexOf(e[3]) < 0 ? e[0] + e[1] + '_' + e[4] : e[0] + '_' + e[4];
}
ret[label] = e[2];
}
return ret;
}

//Function - Decode, Wraps the primary decoder function for Chirpstack - SAGE version
function decodeUplink(input) {
var buf = new Buf(input.bytes);
var decoded = {};
var readingsArr = primaryDecoder(buf, input.fPort);
if (TYPE == 'flat') {
decoded['measurements'] = buildFlat(readingsArr);
} else decoded['measurements'] = buildNested(readingsArr);

return { data: decoded };
}

/*Function primaryDecoder
Purpose: Main Entry point of TTN Console Decoder
Args: bytes - An array of bytes from LoRaWan raw payload(Hex Represented)
port - LoRaWan Port that the message came through(set by Definium firmware)
Returns: decoded - An object with data fields as decoded parameter values
*/
function primaryDecoder(buf, p) {
var arr = [];
var byte = 0;

//Data Packet Recieved
if (p == 1) {
var src = 'main';
arr.push(['packet-type', 0, 'DATA_PACKET', src]);
arr.push(['uncorrected-outer', 0, +buf.readFloatLE(byte).toFixed(3), src, 'cm/hr']);
arr.push(['uncorrected-inner', 0, +buf.readFloatLE((byte = byte + 4)).toFixed(3), src, 'cm/hr']);
arr.push(['corrected-outer', 0, +buf.readFloatLE((byte = byte + 4)).toFixed(3), src, 'cm/hr']);
arr.push(['corrected-inner', 0, +buf.readFloatLE((byte = byte + 4)).toFixed(3), src, 'cm/hr']);
arr.push(['battery-voltage', 0, +(buf.readUInt16LE((byte = byte + 4)) / 100).toFixed(2), src, 'V']);
arr.push(['external-power-supply-voltage', 0, +(buf.readUInt16LE((byte = byte + 2)) / 100).toFixed(2), src, 'V']);
} else if (p == 10) {
var src = 'device_info';
arr.push(['packet-type', 0, 'DEVICE_INFO', 'main']);

var fw_main = buf.readInt16LE(byte).toString();
fw_main = 'R' + fw_main[0] + '-' + fw_main.slice(1, 3).replace(/^(0)?/, '') + '-' + fw_main.slice(3, fw_main.length).replace(/^(0)?/, '');
arr.push(['firmware-mainboard', 0, fw_main, src]);

var fw_ucmi = buf.readInt16LE((byte = byte + 2)).toString();
var region = ['a', 'e', 'c', 's', 'u'];
var ucmi_reg = region[+fw_ucmi[fw_ucmi.length - 1]];
fw_ucmi = 'R' + fw_ucmi[0] + '-' + fw_ucmi[1] + '-' + fw_ucmi.slice(2, 4).replace(/^(0)?/, '') + ucmi_reg;
arr.push(['firmware-ucmi', 0, fw_ucmi, src]);

arr.push(['vs-factor', 0, +(buf.readInt16LE((byte = byte + 2)) / 1000).toFixed(4), src]);
arr.push(['outer-area', 0, +(buf.readInt16LE((byte = byte + 2)) / 1000).toFixed(3), src, 'cm^2']);
arr.push(['inner-area', 0, +(buf.readInt16LE((byte = byte + 2)) / 1000).toFixed(3), src, 'cm^2']);
} else if (p === 100) {
//Downlink Response Packet Recieved
arr.push(['packet-type', 0, 'DOWNLINK_RESPONSE', 'main']);
arr.push(['downlink-response', 0, String.fromCharCode.apply(String, buf.slice(0, buf.length)), 'downlink']);
} else {
// Unknown Response Recieved
arr.push(['packet-type', 0, 'UNKNOWN_RESPONSE', 'main']);
arr.push(['raw-payload', 0, buf.slice(0, buf.length), 'unknown']);
}

return arr;
}
11 changes: 11 additions & 0 deletions vendor/ict-international/sfm1x-r3-1-codec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Uplink decoder decodes binary data uplink into a JSON object (optional)
uplinkDecoder:
fileName: sfm1x-r3-1.js

# Downlink encoder encodes JSON object into a binary data downlink (optional)
downlinkEncoder:
fileName: sfm1x-r3-1.js

# Downlink decoder decodes the encoded downlink message (optional, must be symmetric with downlinkEncoder)
downlinkDecoder:
fileName: sfm1x-r3-1.js
Loading

0 comments on commit feb47c9

Please sign in to comment.