chore: enforce prettier configuration

In order to avoid reformatting of the code this PR add a prettier configuration as well as scripts to automatically format apply the rules
This commit is contained in:
Luc Patiny 2025-11-17 06:10:08 +01:00
parent f6fea65063
commit 3f899c8445
19 changed files with 3477 additions and 3474 deletions

7
.prettierrc Normal file
View file

@ -0,0 +1,7 @@
{
"arrowParens": "always",
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "all"
}

19
package-lock.json generated
View file

@ -11,6 +11,9 @@
"dependencies": {
"@noble/curves": "^1.8.1",
"serialport": "^13.0.0"
},
"devDependencies": {
"prettier": "^3.6.2"
}
},
"node_modules/@noble/curves": {
@ -266,6 +269,22 @@
"node-gyp-build-test": "build-test.js"
}
},
"node_modules/prettier": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
"dev": true,
"license": "MIT",
"bin": {
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/serialport": {
"version": "13.0.0",
"resolved": "https://registry.npmjs.org/serialport/-/serialport-13.0.0.tgz",

View file

@ -5,6 +5,8 @@
"main": "src/index.js",
"type": "module",
"scripts": {
"prettier": "prettier --check src",
"prettier-write": "prettier --write src",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Liam Cottle <liam@liamcottle.com>",
@ -12,5 +14,8 @@
"dependencies": {
"@noble/curves": "^1.8.1",
"serialport": "^13.0.0"
},
"devDependencies": {
"prettier": "^3.6.2"
}
}

View file

@ -1,101 +1,97 @@
import BufferReader from "./buffer_reader.js";
import BufferWriter from "./buffer_writer.js";
import BufferReader from './buffer_reader.js';
import BufferWriter from './buffer_writer.js';
class Advert {
static ADV_TYPE_NONE = 0;
static ADV_TYPE_CHAT = 1;
static ADV_TYPE_REPEATER = 2;
static ADV_TYPE_ROOM = 3;
static ADV_TYPE_NONE = 0;
static ADV_TYPE_CHAT = 1;
static ADV_TYPE_REPEATER = 2;
static ADV_TYPE_ROOM = 3;
static ADV_LATLON_MASK = 0x10;
static ADV_BATTERY_MASK = 0x20;
static ADV_TEMPERATURE_MASK = 0x40;
static ADV_NAME_MASK = 0x80;
static ADV_LATLON_MASK = 0x10;
static ADV_BATTERY_MASK = 0x20;
static ADV_TEMPERATURE_MASK = 0x40;
static ADV_NAME_MASK = 0x80;
constructor(publicKey, timestamp, signature, appData) {
this.publicKey = publicKey;
this.timestamp = timestamp;
this.signature = signature;
this.appData = appData;
this.parsed = this.parseAppData();
}
constructor(publicKey, timestamp, signature, appData) {
this.publicKey = publicKey;
this.timestamp = timestamp;
this.signature = signature;
this.appData = appData;
this.parsed = this.parseAppData();
static fromBytes(bytes) {
// read bytes
const bufferReader = new BufferReader(bytes);
const publicKey = bufferReader.readBytes(32);
const timestamp = bufferReader.readUInt32LE();
const signature = bufferReader.readBytes(64);
const appData = bufferReader.readRemainingBytes();
return new Advert(publicKey, timestamp, signature, appData);
}
getFlags() {
return this.appData[0];
}
getType() {
const flags = this.getFlags();
return flags & 0x0f;
}
getTypeString() {
const type = this.getType();
if (type === Advert.ADV_TYPE_NONE) return 'NONE';
if (type === Advert.ADV_TYPE_CHAT) return 'CHAT';
if (type === Advert.ADV_TYPE_REPEATER) return 'REPEATER';
if (type === Advert.ADV_TYPE_ROOM) return 'ROOM';
return null;
}
async isVerified() {
const { ed25519 } = await import('@noble/curves/ed25519');
// build signed data
const bufferWriter = new BufferWriter();
bufferWriter.writeBytes(this.publicKey);
bufferWriter.writeUInt32LE(this.timestamp);
bufferWriter.writeBytes(this.appData);
// verify signature
return ed25519.verify(
this.signature,
bufferWriter.toBytes(),
this.publicKey,
);
}
parseAppData() {
// read app data
const bufferReader = new BufferReader(this.appData);
const flags = bufferReader.readByte();
// parse lat lon
var lat = null;
var lon = null;
if (flags & Advert.ADV_LATLON_MASK) {
lat = bufferReader.readInt32LE();
lon = bufferReader.readInt32LE();
}
static fromBytes(bytes) {
// read bytes
const bufferReader = new BufferReader(bytes);
const publicKey = bufferReader.readBytes(32);
const timestamp = bufferReader.readUInt32LE();
const signature = bufferReader.readBytes(64);
const appData = bufferReader.readRemainingBytes();
return new Advert(publicKey, timestamp, signature, appData);
}
getFlags() {
return this.appData[0];
}
getType() {
const flags = this.getFlags();
return flags & 0x0F;
}
getTypeString() {
const type = this.getType();
if(type === Advert.ADV_TYPE_NONE) return "NONE";
if(type === Advert.ADV_TYPE_CHAT) return "CHAT";
if(type === Advert.ADV_TYPE_REPEATER) return "REPEATER";
if(type === Advert.ADV_TYPE_ROOM) return "ROOM";
return null;
}
async isVerified() {
const { ed25519 } = await import("@noble/curves/ed25519");
// build signed data
const bufferWriter = new BufferWriter();
bufferWriter.writeBytes(this.publicKey);
bufferWriter.writeUInt32LE(this.timestamp);
bufferWriter.writeBytes(this.appData);
// verify signature
return ed25519.verify(this.signature, bufferWriter.toBytes(), this.publicKey);
}
parseAppData() {
// read app data
const bufferReader = new BufferReader(this.appData);
const flags = bufferReader.readByte();
// parse lat lon
var lat = null;
var lon = null;
if(flags & Advert.ADV_LATLON_MASK){
lat = bufferReader.readInt32LE();
lon = bufferReader.readInt32LE();
}
// parse name (remainder of app data)
var name = null;
if(flags & Advert.ADV_NAME_MASK){
name = bufferReader.readString();
}
return {
type: this.getTypeString(),
lat: lat,
lon: lon,
name: name,
};
// parse name (remainder of app data)
var name = null;
if (flags & Advert.ADV_NAME_MASK) {
name = bufferReader.readString();
}
return {
type: this.getTypeString(),
lat: lat,
lon: lon,
name: name,
};
}
}
export default Advert;

View file

@ -1,118 +1,113 @@
class BufferReader {
constructor(data) {
this.pointer = 0;
this.buffer = new Uint8Array(data);
}
constructor(data) {
this.pointer = 0;
this.buffer = new Uint8Array(data);
}
getRemainingBytesCount() {
return this.buffer.length - this.pointer;
}
readByte() {
return this.readBytes(1)[0];
}
readBytes(count) {
const data = this.buffer.slice(this.pointer, this.pointer + count);
this.pointer += count;
return data;
}
readRemainingBytes() {
return this.readBytes(this.getRemainingBytesCount());
}
readString() {
return new TextDecoder().decode(this.readRemainingBytes());
}
readCString(maxLength) {
const value = [];
const bytes = this.readBytes(maxLength);
for(const byte of bytes){
// if we find a null terminator character, we have reached the end of the cstring
if(byte === 0){
return new TextDecoder().decode(new Uint8Array(value));
}
value.push(byte);
}
}
readInt8() {
const bytes = this.readBytes(1);
const view = new DataView(bytes.buffer);
return view.getInt8(0);
}
readUInt8() {
const bytes = this.readBytes(1);
const view = new DataView(bytes.buffer);
return view.getUint8(0);
}
readUInt16LE() {
const bytes = this.readBytes(2);
const view = new DataView(bytes.buffer);
return view.getUint16(0, true);
}
readUInt16BE() {
const bytes = this.readBytes(2);
const view = new DataView(bytes.buffer);
return view.getUint16(0, false);
}
readUInt32LE() {
const bytes = this.readBytes(4);
const view = new DataView(bytes.buffer);
return view.getUint32(0, true);
}
readUInt32BE() {
const bytes = this.readBytes(4);
const view = new DataView(bytes.buffer);
return view.getUint32(0, false);
}
readInt16LE() {
const bytes = this.readBytes(2);
const view = new DataView(bytes.buffer);
return view.getInt16(0, true);
}
readInt16BE() {
const bytes = this.readBytes(2);
const view = new DataView(bytes.buffer);
return view.getInt16(0, false);
}
readInt32LE() {
const bytes = this.readBytes(4);
const view = new DataView(bytes.buffer);
return view.getInt32(0, true);
}
readInt24BE() {
// read 24-bit (3 bytes) big endian integer
var value = (this.readByte() << 16) | (this.readByte() << 8) | this.readByte();
// convert 24-bit signed integer to 32-bit signed integer
// 0x800000 is the sign bit for a 24-bit value
// if it's set, value is negative in 24-bit two's complement
// so we subtract 0x1000000 (which is 2^24) to get the correct negative value as a Dart integer
if((value & 0x800000) !== 0){
value -= 0x1000000;
}
return value;
getRemainingBytesCount() {
return this.buffer.length - this.pointer;
}
readByte() {
return this.readBytes(1)[0];
}
readBytes(count) {
const data = this.buffer.slice(this.pointer, this.pointer + count);
this.pointer += count;
return data;
}
readRemainingBytes() {
return this.readBytes(this.getRemainingBytesCount());
}
readString() {
return new TextDecoder().decode(this.readRemainingBytes());
}
readCString(maxLength) {
const value = [];
const bytes = this.readBytes(maxLength);
for (const byte of bytes) {
// if we find a null terminator character, we have reached the end of the cstring
if (byte === 0) {
return new TextDecoder().decode(new Uint8Array(value));
}
value.push(byte);
}
}
readInt8() {
const bytes = this.readBytes(1);
const view = new DataView(bytes.buffer);
return view.getInt8(0);
}
readUInt8() {
const bytes = this.readBytes(1);
const view = new DataView(bytes.buffer);
return view.getUint8(0);
}
readUInt16LE() {
const bytes = this.readBytes(2);
const view = new DataView(bytes.buffer);
return view.getUint16(0, true);
}
readUInt16BE() {
const bytes = this.readBytes(2);
const view = new DataView(bytes.buffer);
return view.getUint16(0, false);
}
readUInt32LE() {
const bytes = this.readBytes(4);
const view = new DataView(bytes.buffer);
return view.getUint32(0, true);
}
readUInt32BE() {
const bytes = this.readBytes(4);
const view = new DataView(bytes.buffer);
return view.getUint32(0, false);
}
readInt16LE() {
const bytes = this.readBytes(2);
const view = new DataView(bytes.buffer);
return view.getInt16(0, true);
}
readInt16BE() {
const bytes = this.readBytes(2);
const view = new DataView(bytes.buffer);
return view.getInt16(0, false);
}
readInt32LE() {
const bytes = this.readBytes(4);
const view = new DataView(bytes.buffer);
return view.getInt32(0, true);
}
readInt24BE() {
// read 24-bit (3 bytes) big endian integer
var value =
(this.readByte() << 16) | (this.readByte() << 8) | this.readByte();
// convert 24-bit signed integer to 32-bit signed integer
// 0x800000 is the sign bit for a 24-bit value
// if it's set, value is negative in 24-bit two's complement
// so we subtract 0x1000000 (which is 2^24) to get the correct negative value as a Dart integer
if ((value & 0x800000) !== 0) {
value -= 0x1000000;
}
return value;
}
}
export default BufferReader;

View file

@ -1,40 +1,40 @@
class BufferUtils {
static bytesToHex(uint8Array) {
return Array.from(uint8Array)
.map((byte) => {
return byte.toString(16).padStart(2, '0');
})
.join('');
}
static bytesToHex(uint8Array) {
return Array.from(uint8Array).map(byte => {
return byte.toString(16).padStart(2, '0');
}).join('');
static hexToBytes(hex) {
return Uint8Array.from(
hex.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)),
);
}
static base64ToBytes(base64) {
return Uint8Array.from(atob(base64), (c) => {
return c.charCodeAt(0);
});
}
static areBuffersEqual(byteArray1, byteArray2) {
// ensure length is the same
if (byteArray1.length !== byteArray2.length) {
return false;
}
static hexToBytes(hex) {
return Uint8Array.from(hex.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));
}
static base64ToBytes(base64) {
return Uint8Array.from(atob(base64), (c) => {
return c.charCodeAt(0);
});
}
static areBuffersEqual(byteArray1, byteArray2) {
// ensure length is the same
if(byteArray1.length !== byteArray2.length){
return false;
}
// ensure each item is the same
for(let i = 0; i < byteArray1.length; i++){
if(byteArray1[i] !== byteArray2[i]){
return false;
}
}
// arrays are the same
return true;
// ensure each item is the same
for (let i = 0; i < byteArray1.length; i++) {
if (byteArray1[i] !== byteArray2[i]) {
return false;
}
}
// arrays are the same
return true;
}
}
export default BufferUtils;

View file

@ -1,72 +1,63 @@
class BufferWriter {
constructor() {
this.buffer = [];
}
constructor() {
this.buffer = [];
toBytes() {
return new Uint8Array(this.buffer);
}
writeBytes(bytes) {
this.buffer = [...this.buffer, ...bytes];
}
writeByte(byte) {
this.writeBytes([byte]);
}
writeUInt16LE(num) {
const bytes = new Uint8Array(2);
const view = new DataView(bytes.buffer);
view.setUint16(0, num, true);
this.writeBytes(bytes);
}
writeUInt32LE(num) {
const bytes = new Uint8Array(4);
const view = new DataView(bytes.buffer);
view.setUint32(0, num, true);
this.writeBytes(bytes);
}
writeInt32LE(num) {
const bytes = new Uint8Array(4);
const view = new DataView(bytes.buffer);
view.setInt32(0, num, true);
this.writeBytes(bytes);
}
writeString(string) {
this.writeBytes(new TextEncoder().encode(string));
}
writeCString(string, maxLength) {
// create buffer of max length
const bytes = new Uint8Array(new ArrayBuffer(maxLength));
// encode string to bytes
const encodedString = new TextEncoder().encode(string);
// copy in string until we hit the max length, or we run out of string bytes
for (var i = 0; i < maxLength && i < encodedString.length; i++) {
bytes[i] = encodedString[i];
}
toBytes() {
return new Uint8Array(this.buffer);
}
writeBytes(bytes) {
this.buffer = [
...this.buffer,
...bytes,
];
}
writeByte(byte) {
this.writeBytes([
byte,
]);
}
writeUInt16LE(num) {
const bytes = new Uint8Array(2);
const view = new DataView(bytes.buffer);
view.setUint16(0, num, true);
this.writeBytes(bytes);
}
writeUInt32LE(num) {
const bytes = new Uint8Array(4);
const view = new DataView(bytes.buffer);
view.setUint32(0, num, true);
this.writeBytes(bytes);
}
writeInt32LE(num) {
const bytes = new Uint8Array(4);
const view = new DataView(bytes.buffer);
view.setInt32(0, num, true);
this.writeBytes(bytes);
}
writeString(string) {
this.writeBytes(new TextEncoder().encode(string));
}
writeCString(string, maxLength) {
// create buffer of max length
const bytes = new Uint8Array(new ArrayBuffer(maxLength));
// encode string to bytes
const encodedString = new TextEncoder().encode(string);
// copy in string until we hit the max length, or we run out of string bytes
for(var i = 0; i < maxLength && i < encodedString.length; i++){
bytes[i] = encodedString[i];
}
// ensure the last byte is always a null terminator
bytes[bytes.length - 1] = 0;
// write to buffer
this.writeBytes(bytes);
}
// ensure the last byte is always a null terminator
bytes[bytes.length - 1] = 0;
// write to buffer
this.writeBytes(bytes);
}
}
export default BufferWriter;

View file

@ -1,196 +1,192 @@
import BufferReader from "./buffer_reader.js";
import BufferReader from './buffer_reader.js';
class CayenneLpp {
static LPP_DIGITAL_INPUT = 0; // 1 byte
static LPP_DIGITAL_OUTPUT = 1; // 1 byte
static LPP_ANALOG_INPUT = 2; // 2 bytes, 0.01 signed
static LPP_ANALOG_OUTPUT = 3; // 2 bytes, 0.01 signed
static LPP_GENERIC_SENSOR = 100; // 4 bytes, unsigned
static LPP_LUMINOSITY = 101; // 2 bytes, 1 lux unsigned
static LPP_PRESENCE = 102; // 1 byte, bool
static LPP_TEMPERATURE = 103; // 2 bytes, 0.1°C signed
static LPP_RELATIVE_HUMIDITY = 104; // 1 byte, 0.5% unsigned
static LPP_ACCELEROMETER = 113; // 2 bytes per axis, 0.001G
static LPP_BAROMETRIC_PRESSURE = 115; // 2 bytes 0.1hPa unsigned
static LPP_VOLTAGE = 116; // 2 bytes 0.01V unsigned
static LPP_CURRENT = 117; // 2 bytes 0.001A unsigned
static LPP_FREQUENCY = 118; // 4 bytes 1Hz unsigned
static LPP_PERCENTAGE = 120; // 1 byte 1-100% unsigned
static LPP_ALTITUDE = 121; // 2 byte 1m signed
static LPP_CONCENTRATION = 125; // 2 bytes, 1 ppm unsigned
static LPP_POWER = 128; // 2 byte, 1W, unsigned
static LPP_DISTANCE = 130; // 4 byte, 0.001m, unsigned
static LPP_ENERGY = 131; // 4 byte, 0.001kWh, unsigned
static LPP_DIRECTION = 132; // 2 bytes, 1deg, unsigned
static LPP_UNIXTIME = 133; // 4 bytes, unsigned
static LPP_GYROMETER = 134; // 2 bytes per axis, 0.01 °/s
static LPP_COLOUR = 135; // 1 byte per RGB Color
static LPP_GPS = 136; // 3 byte lon/lat 0.0001 °, 3 bytes alt 0.01 meter
static LPP_SWITCH = 142; // 1 byte, 0/1
static LPP_POLYLINE = 240; // 1 byte size, 1 byte delta factor, 3 byte lon/lat 0.0001° * factor, n (size-8) bytes deltas
static LPP_DIGITAL_INPUT = 0; // 1 byte
static LPP_DIGITAL_OUTPUT = 1; // 1 byte
static LPP_ANALOG_INPUT = 2; // 2 bytes, 0.01 signed
static LPP_ANALOG_OUTPUT = 3; // 2 bytes, 0.01 signed
static LPP_GENERIC_SENSOR = 100; // 4 bytes, unsigned
static LPP_LUMINOSITY = 101; // 2 bytes, 1 lux unsigned
static LPP_PRESENCE = 102; // 1 byte, bool
static LPP_TEMPERATURE = 103; // 2 bytes, 0.1°C signed
static LPP_RELATIVE_HUMIDITY = 104; // 1 byte, 0.5% unsigned
static LPP_ACCELEROMETER = 113; // 2 bytes per axis, 0.001G
static LPP_BAROMETRIC_PRESSURE = 115; // 2 bytes 0.1hPa unsigned
static LPP_VOLTAGE = 116; // 2 bytes 0.01V unsigned
static LPP_CURRENT = 117; // 2 bytes 0.001A unsigned
static LPP_FREQUENCY = 118; // 4 bytes 1Hz unsigned
static LPP_PERCENTAGE = 120; // 1 byte 1-100% unsigned
static LPP_ALTITUDE = 121; // 2 byte 1m signed
static LPP_CONCENTRATION = 125; // 2 bytes, 1 ppm unsigned
static LPP_POWER = 128; // 2 byte, 1W, unsigned
static LPP_DISTANCE = 130; // 4 byte, 0.001m, unsigned
static LPP_ENERGY = 131; // 4 byte, 0.001kWh, unsigned
static LPP_DIRECTION = 132; // 2 bytes, 1deg, unsigned
static LPP_UNIXTIME = 133; // 4 bytes, unsigned
static LPP_GYROMETER = 134; // 2 bytes per axis, 0.01 °/s
static LPP_COLOUR = 135; // 1 byte per RGB Color
static LPP_GPS = 136; // 3 byte lon/lat 0.0001 °, 3 bytes alt 0.01 meter
static LPP_SWITCH = 142; // 1 byte, 0/1
static LPP_POLYLINE = 240; // 1 byte size, 1 byte delta factor, 3 byte lon/lat 0.0001° * factor, n (size-8) bytes deltas
static parse(bytes) {
const buffer = new BufferReader(bytes);
const telemetry = [];
static parse(bytes) {
while (buffer.getRemainingBytesCount() >= 2) {
// need at least 2 more bytes to get channel and type
const buffer = new BufferReader(bytes);
const telemetry = [];
const channel = buffer.readUInt8();
const type = buffer.readUInt8();
while(buffer.getRemainingBytesCount() >= 2){ // need at least 2 more bytes to get channel and type
const channel = buffer.readUInt8();
const type = buffer.readUInt8();
// stop parsing if channel and type are zero, as there seems to be garbage bytes???
if(channel === 0 && type === 0){
break;
}
switch(type){
case this.LPP_GENERIC_SENSOR: {
const value = buffer.readUInt32BE();
// console.log(`[CayenneLpp] parsed LPP_GENERIC_SENSOR=${value}`);
telemetry.push({
"channel": channel,
"type": type,
"value": value,
});
break;
}
case this.LPP_LUMINOSITY: {
const lux = buffer.readInt16BE();
// console.log(`[CayenneLpp] parsed LPP_LUMINOSITY=${lux}`);
telemetry.push({
"channel": channel,
"type": type,
"value": lux,
});
break;
}
case this.LPP_PRESENCE: {
const presence = buffer.readUInt8();
// console.log(`[CayenneLpp] parsed LPP_PRESENCE=${presence}`);
telemetry.push({
"channel": channel,
"type": type,
"value": presence,
});
break;
}
case this.LPP_TEMPERATURE: {
const temperature = buffer.readInt16BE() / 10;
// console.log(`[CayenneLpp] parsed LPP_TEMPERATURE=${temperature}`);
telemetry.push({
"channel": channel,
"type": type,
"value": temperature,
});
break;
}
case this.LPP_RELATIVE_HUMIDITY: {
const relativeHumidity = buffer.readUInt8() / 2;
// console.log(`[CayenneLpp] parsed LPP_RELATIVE_HUMIDITY=${relativeHumidity}`);
telemetry.push({
"channel": channel,
"type": type,
"value": relativeHumidity,
});
break;
}
case this.LPP_BAROMETRIC_PRESSURE: {
const barometricPressure = buffer.readUInt16BE() / 10;
// console.log(`[CayenneLpp] parsed LPP_BAROMETRIC_PRESSURE=${barometricPressure}`);
telemetry.push({
"channel": channel,
"type": type,
"value": barometricPressure,
});
break;
}
case this.LPP_VOLTAGE: {
// uint16: 0v to 655.35v
// int16: -327.67v to +327.67v
// should be readUInt16BE, but I'm using readInt16BE to allow for negative voltage
const voltage = buffer.readInt16BE() / 100;
// console.log(`[CayenneLpp] parsed LPP_VOLTAGE=${voltage}`);
telemetry.push({
"channel": channel,
"type": type,
"value": voltage,
});
break;
}
case this.LPP_CURRENT: {
// uint16: 0A to 655.35A
// int16: -327.67A to +327.67A
// should be readUInt16BE, but I'm using readInt16BE to allow for negative current
const current = buffer.readInt16BE() / 1000;
// console.log(`[CayenneLpp] parsed LPP_CURRENT=${current}`);
telemetry.push({
"channel": channel,
"type": type,
"value": current,
});
break;
}
case this.LPP_PERCENTAGE: {
const percentage = buffer.readUInt8();
// console.log(`[CayenneLpp] parsed LPP_PERCENTAGE=${percentage}`);
telemetry.push({
"channel": channel,
"type": type,
"value": percentage,
});
break;
}
case this.LPP_CONCENTRATION: {
const concentration = buffer.readUInt16BE();
// console.log(`[CayenneLpp] parsed LPP_CONCENTRATION=${concentration}`);
telemetry.push({
"channel": channel,
"type": type,
"value": concentration,
});
break;
}
case this.LPP_POWER: {
const power = buffer.readUInt16BE();
// console.log(`[CayenneLpp] parsed LPP_POWER=${power}`);
telemetry.push({
"channel": channel,
"type": type,
"value": power,
});
break;
}
case this.LPP_GPS: {
const latitude = buffer.readInt24BE() / 10000;
const longitude = buffer.readInt24BE() / 10000;
const altitude = buffer.readInt24BE() / 100;
// console.log(`[CayenneLpp] parsed LPP_GPS=${latitude},${longitude},${altitude}`);
telemetry.push({
"channel": channel,
"type": type,
"value": {
latitude: latitude,
longitude: longitude,
altitude: altitude,
},
});
break;
}
// todo support all telemetry types, otherwise if an unknown is given, we can't read other telemetry after it
default: {
// console.log(`[CayenneLpp] unsupported type: ${type}`);
return telemetry;
}
}
// stop parsing if channel and type are zero, as there seems to be garbage bytes???
if (channel === 0 && type === 0) {
break;
}
switch (type) {
case this.LPP_GENERIC_SENSOR: {
const value = buffer.readUInt32BE();
// console.log(`[CayenneLpp] parsed LPP_GENERIC_SENSOR=${value}`);
telemetry.push({
channel: channel,
type: type,
value: value,
});
break;
}
return telemetry;
case this.LPP_LUMINOSITY: {
const lux = buffer.readInt16BE();
// console.log(`[CayenneLpp] parsed LPP_LUMINOSITY=${lux}`);
telemetry.push({
channel: channel,
type: type,
value: lux,
});
break;
}
case this.LPP_PRESENCE: {
const presence = buffer.readUInt8();
// console.log(`[CayenneLpp] parsed LPP_PRESENCE=${presence}`);
telemetry.push({
channel: channel,
type: type,
value: presence,
});
break;
}
case this.LPP_TEMPERATURE: {
const temperature = buffer.readInt16BE() / 10;
// console.log(`[CayenneLpp] parsed LPP_TEMPERATURE=${temperature}`);
telemetry.push({
channel: channel,
type: type,
value: temperature,
});
break;
}
case this.LPP_RELATIVE_HUMIDITY: {
const relativeHumidity = buffer.readUInt8() / 2;
// console.log(`[CayenneLpp] parsed LPP_RELATIVE_HUMIDITY=${relativeHumidity}`);
telemetry.push({
channel: channel,
type: type,
value: relativeHumidity,
});
break;
}
case this.LPP_BAROMETRIC_PRESSURE: {
const barometricPressure = buffer.readUInt16BE() / 10;
// console.log(`[CayenneLpp] parsed LPP_BAROMETRIC_PRESSURE=${barometricPressure}`);
telemetry.push({
channel: channel,
type: type,
value: barometricPressure,
});
break;
}
case this.LPP_VOLTAGE: {
// uint16: 0v to 655.35v
// int16: -327.67v to +327.67v
// should be readUInt16BE, but I'm using readInt16BE to allow for negative voltage
const voltage = buffer.readInt16BE() / 100;
// console.log(`[CayenneLpp] parsed LPP_VOLTAGE=${voltage}`);
telemetry.push({
channel: channel,
type: type,
value: voltage,
});
break;
}
case this.LPP_CURRENT: {
// uint16: 0A to 655.35A
// int16: -327.67A to +327.67A
// should be readUInt16BE, but I'm using readInt16BE to allow for negative current
const current = buffer.readInt16BE() / 1000;
// console.log(`[CayenneLpp] parsed LPP_CURRENT=${current}`);
telemetry.push({
channel: channel,
type: type,
value: current,
});
break;
}
case this.LPP_PERCENTAGE: {
const percentage = buffer.readUInt8();
// console.log(`[CayenneLpp] parsed LPP_PERCENTAGE=${percentage}`);
telemetry.push({
channel: channel,
type: type,
value: percentage,
});
break;
}
case this.LPP_CONCENTRATION: {
const concentration = buffer.readUInt16BE();
// console.log(`[CayenneLpp] parsed LPP_CONCENTRATION=${concentration}`);
telemetry.push({
channel: channel,
type: type,
value: concentration,
});
break;
}
case this.LPP_POWER: {
const power = buffer.readUInt16BE();
// console.log(`[CayenneLpp] parsed LPP_POWER=${power}`);
telemetry.push({
channel: channel,
type: type,
value: power,
});
break;
}
case this.LPP_GPS: {
const latitude = buffer.readInt24BE() / 10000;
const longitude = buffer.readInt24BE() / 10000;
const altitude = buffer.readInt24BE() / 100;
// console.log(`[CayenneLpp] parsed LPP_GPS=${latitude},${longitude},${altitude}`);
telemetry.push({
channel: channel,
type: type,
value: {
latitude: latitude,
longitude: longitude,
altitude: altitude,
},
});
break;
}
// todo support all telemetry types, otherwise if an unknown is given, we can't read other telemetry after it
default: {
// console.log(`[CayenneLpp] unsupported type: ${type}`);
return telemetry;
}
}
}
return telemetry;
}
}
export default CayenneLpp;

File diff suppressed because it is too large Load diff

View file

@ -1,60 +1,56 @@
import SerialConnection from "./serial_connection.js";
import SerialConnection from './serial_connection.js';
class NodeJSSerialConnection extends SerialConnection {
/**
* @param path serial port to connect to, e.g: "/dev/ttyACM0" or "/dev/cu.usbmodem14401"
*/
constructor(path) {
super();
this.serialPortPath = path;
}
/**
* @param path serial port to connect to, e.g: "/dev/ttyACM0" or "/dev/cu.usbmodem14401"
*/
constructor(path) {
super();
this.serialPortPath = path;
}
async connect() {
// note: serialport module is only available in NodeJS, you shouldn't use NodeJSSerialConnection from a web browser
const { SerialPort } = await import('serialport');
// create new serial port
this.serialPort = new SerialPort({
autoOpen: false, // don't auto open, we want to control this manually
path: this.serialPortPath, // e.g: "/dev/ttyACM0" or "/dev/cu.usbmodem14401"
baudRate: 115200,
});
this.serialPort.on("open", async () => {
await this.onConnected();
});
this.serialPort.on("close", () => {
this.onDisconnected();
});
this.serialPort.on("error", function(err) {
console.log("SerialPort Error: ", err.message)
});
this.serialPort.on("data", async (data) => {
await this.onDataReceived(data);
});
// open serial connection
this.serialPort.open();
}
async close() {
try {
await this.serialPort.close();
} catch(e) {
console.log("failed to close serial port, ignoring...", e);
}
}
/* override */ async write(bytes) {
this.serialPort.write(bytes);
async connect() {
// note: serialport module is only available in NodeJS, you shouldn't use NodeJSSerialConnection from a web browser
const { SerialPort } = await import('serialport');
// create new serial port
this.serialPort = new SerialPort({
autoOpen: false, // don't auto open, we want to control this manually
path: this.serialPortPath, // e.g: "/dev/ttyACM0" or "/dev/cu.usbmodem14401"
baudRate: 115200,
});
this.serialPort.on('open', async () => {
await this.onConnected();
});
this.serialPort.on('close', () => {
this.onDisconnected();
});
this.serialPort.on('error', function (err) {
console.log('SerialPort Error: ', err.message);
});
this.serialPort.on('data', async (data) => {
await this.onDataReceived(data);
});
// open serial connection
this.serialPort.open();
}
async close() {
try {
await this.serialPort.close();
} catch (e) {
console.log('failed to close serial port, ignoring...', e);
}
}
/* override */ async write(bytes) {
this.serialPort.write(bytes);
}
}
export default NodeJSSerialConnection;

View file

@ -1,99 +1,100 @@
import BufferWriter from "../buffer_writer.js";
import BufferReader from "../buffer_reader.js";
import Constants from "../constants.js";
import Connection from "./connection.js";
import BufferWriter from '../buffer_writer.js';
import BufferReader from '../buffer_reader.js';
import Constants from '../constants.js';
import Connection from './connection.js';
class SerialConnection extends Connection {
constructor() {
super();
this.readBuffer = [];
if(this.constructor === SerialConnection){
throw new Error("SerialConnection is an abstract class and can't be instantiated.");
}
constructor() {
super();
this.readBuffer = [];
if (this.constructor === SerialConnection) {
throw new Error(
"SerialConnection is an abstract class and can't be instantiated.",
);
}
}
async write(bytes) {
throw new Error("Not Implemented: write must be implemented by SerialConnection sub class.");
}
async write(bytes) {
throw new Error(
'Not Implemented: write must be implemented by SerialConnection sub class.',
);
}
async writeFrame(frameType, frameData) {
async writeFrame(frameType, frameData) {
// create frame
const frame = new BufferWriter();
// create frame
const frame = new BufferWriter();
// add frame header
frame.writeByte(frameType);
frame.writeUInt16LE(frameData.length);
// add frame header
frame.writeByte(frameType);
frame.writeUInt16LE(frameData.length);
// add frame data
frame.writeBytes(frameData);
// add frame data
frame.writeBytes(frameData);
// write frame to device
await this.write(frame.toBytes());
}
// write frame to device
await this.write(frame.toBytes());
async sendToRadioFrame(data) {
// write "app to radio" frame 0x3c "<"
this.emit('tx', data);
await this.writeFrame(0x3c, data);
}
}
async onDataReceived(value) {
// append received bytes to read buffer
this.readBuffer = [...this.readBuffer, ...value];
async sendToRadioFrame(data) {
// write "app to radio" frame 0x3c "<"
this.emit("tx", data);
await this.writeFrame(0x3c, data);
}
// process read buffer while there is enough bytes for a frame header
// 3 bytes frame header = (1 byte frame type) + (2 bytes frame length as unsigned 16-bit little endian)
const frameHeaderLength = 3;
while (this.readBuffer.length >= frameHeaderLength) {
try {
// extract frame header
const frameHeader = new BufferReader(
this.readBuffer.slice(0, frameHeaderLength),
);
async onDataReceived(value) {
// append received bytes to read buffer
this.readBuffer = [
...this.readBuffer,
...value,
];
// process read buffer while there is enough bytes for a frame header
// 3 bytes frame header = (1 byte frame type) + (2 bytes frame length as unsigned 16-bit little endian)
const frameHeaderLength = 3;
while(this.readBuffer.length >= frameHeaderLength){
try {
// extract frame header
const frameHeader = new BufferReader(this.readBuffer.slice(0, frameHeaderLength));
// ensure frame type supported
const frameType = frameHeader.readByte();
if(frameType !== Constants.SerialFrameTypes.Incoming && frameType !== Constants.SerialFrameTypes.Outgoing){
// unexpected byte, lets skip it and try again
this.readBuffer = this.readBuffer.slice(1);
continue;
}
// ensure frame length valid
const frameLength = frameHeader.readUInt16LE();
if(!frameLength){
// unexpected byte, lets skip it and try again
this.readBuffer = this.readBuffer.slice(1);
continue;
}
// check if we have received enough bytes for this frame, otherwise wait until more bytes received
const requiredLength = frameHeaderLength + frameLength;
if(this.readBuffer.length < requiredLength){
break;
}
// get frame data, and remove it and its frame header from the read buffer
const frameData = this.readBuffer.slice(frameHeaderLength, requiredLength);
this.readBuffer = this.readBuffer.slice(requiredLength);
// handle received frame
this.onFrameReceived(frameData);
} catch(e) {
console.error("Failed to process frame", e);
break;
}
// ensure frame type supported
const frameType = frameHeader.readByte();
if (
frameType !== Constants.SerialFrameTypes.Incoming &&
frameType !== Constants.SerialFrameTypes.Outgoing
) {
// unexpected byte, lets skip it and try again
this.readBuffer = this.readBuffer.slice(1);
continue;
}
}
// ensure frame length valid
const frameLength = frameHeader.readUInt16LE();
if (!frameLength) {
// unexpected byte, lets skip it and try again
this.readBuffer = this.readBuffer.slice(1);
continue;
}
// check if we have received enough bytes for this frame, otherwise wait until more bytes received
const requiredLength = frameHeaderLength + frameLength;
if (this.readBuffer.length < requiredLength) {
break;
}
// get frame data, and remove it and its frame header from the read buffer
const frameData = this.readBuffer.slice(
frameHeaderLength,
requiredLength,
);
this.readBuffer = this.readBuffer.slice(requiredLength);
// handle received frame
this.onFrameReceived(frameData);
} catch (e) {
console.error('Failed to process frame', e);
break;
}
}
}
}
export default SerialConnection;

View file

@ -1,136 +1,131 @@
import BufferWriter from "../buffer_writer.js";
import BufferReader from "../buffer_reader.js";
import Constants from "../constants.js";
import Connection from "./connection.js";
import BufferWriter from '../buffer_writer.js';
import BufferReader from '../buffer_reader.js';
import Constants from '../constants.js';
import Connection from './connection.js';
class TCPConnection extends Connection {
constructor(host, port) {
super();
this.host = host;
this.port = port;
this.readBuffer = [];
}
constructor(host, port) {
super();
this.host = host;
this.port = port;
this.readBuffer = [];
}
async connect() {
// note: net module is only available in NodeJS, you shouldn't use TCPConnection from a web browser
const { Socket } = await import('net');
async connect() {
// create new socket
this.socket = new Socket();
// note: net module is only available in NodeJS, you shouldn't use TCPConnection from a web browser
const { Socket } = await import("net");
// handle received data
this.socket.on('data', (data) => {
this.onSocketDataReceived(data);
});
// create new socket
this.socket = new Socket();
// handle errors
this.socket.on('error', (error) => {
console.error('Connection Error', error);
});
// handle received data
this.socket.on('data', (data) => {
this.onSocketDataReceived(data);
});
// handle socket close
this.socket.on('close', (error) => {
this.onDisconnected();
});
// handle errors
this.socket.on('error', (error) => {
console.error('Connection Error', error);
});
// connect to server
this.socket.connect(this.port, this.host, async () => {
await this.onConnected();
});
}
// handle socket close
this.socket.on('close', (error) => {
this.onDisconnected();
});
onSocketDataReceived(data) {
// append received bytes to read buffer
this.readBuffer = [...this.readBuffer, ...data];
// connect to server
this.socket.connect(this.port, this.host, async () => {
await this.onConnected();
});
// process read buffer while there is enough bytes for a frame header
// 3 bytes frame header = (1 byte frame type) + (2 bytes frame length as unsigned 16-bit little endian)
const frameHeaderLength = 3;
while (this.readBuffer.length >= frameHeaderLength) {
try {
// extract frame header
const frameHeader = new BufferReader(
this.readBuffer.slice(0, frameHeaderLength),
);
}
onSocketDataReceived(data) {
// append received bytes to read buffer
this.readBuffer = [
...this.readBuffer,
...data,
];
// process read buffer while there is enough bytes for a frame header
// 3 bytes frame header = (1 byte frame type) + (2 bytes frame length as unsigned 16-bit little endian)
const frameHeaderLength = 3;
while(this.readBuffer.length >= frameHeaderLength){
try {
// extract frame header
const frameHeader = new BufferReader(this.readBuffer.slice(0, frameHeaderLength));
// ensure frame type supported
const frameType = frameHeader.readByte();
if(frameType !== Constants.SerialFrameTypes.Incoming && frameType !== Constants.SerialFrameTypes.Outgoing){
// unexpected byte, lets skip it and try again
this.readBuffer = this.readBuffer.slice(1);
continue;
}
// ensure frame length valid
const frameLength = frameHeader.readUInt16LE();
if(!frameLength){
// unexpected byte, lets skip it and try again
this.readBuffer = this.readBuffer.slice(1);
continue;
}
// check if we have received enough bytes for this frame, otherwise wait until more bytes received
const requiredLength = frameHeaderLength + frameLength;
if(this.readBuffer.length < requiredLength){
break;
}
// get frame data, and remove it and its frame header from the read buffer
const frameData = this.readBuffer.slice(frameHeaderLength, requiredLength);
this.readBuffer = this.readBuffer.slice(requiredLength);
// handle received frame
this.onFrameReceived(frameData);
} catch(e) {
console.error("Failed to process frame", e);
break;
}
// ensure frame type supported
const frameType = frameHeader.readByte();
if (
frameType !== Constants.SerialFrameTypes.Incoming &&
frameType !== Constants.SerialFrameTypes.Outgoing
) {
// unexpected byte, lets skip it and try again
this.readBuffer = this.readBuffer.slice(1);
continue;
}
}
close() {
try {
this.socket.destroy();
} catch(e) {
// console.log("failed to release lock on serial port readable, ignoring...", e);
// ensure frame length valid
const frameLength = frameHeader.readUInt16LE();
if (!frameLength) {
// unexpected byte, lets skip it and try again
this.readBuffer = this.readBuffer.slice(1);
continue;
}
// check if we have received enough bytes for this frame, otherwise wait until more bytes received
const requiredLength = frameHeaderLength + frameLength;
if (this.readBuffer.length < requiredLength) {
break;
}
// get frame data, and remove it and its frame header from the read buffer
const frameData = this.readBuffer.slice(
frameHeaderLength,
requiredLength,
);
this.readBuffer = this.readBuffer.slice(requiredLength);
// handle received frame
this.onFrameReceived(frameData);
} catch (e) {
console.error('Failed to process frame', e);
break;
}
}
}
async write(bytes) {
this.socket.write(new Uint8Array(bytes));
close() {
try {
this.socket.destroy();
} catch (e) {
// console.log("failed to release lock on serial port readable, ignoring...", e);
}
}
async writeFrame(frameType, frameData) {
async write(bytes) {
this.socket.write(new Uint8Array(bytes));
}
// create frame
const frame = new BufferWriter();
async writeFrame(frameType, frameData) {
// create frame
const frame = new BufferWriter();
// add frame header
frame.writeByte(frameType);
frame.writeUInt16LE(frameData.length);
// add frame header
frame.writeByte(frameType);
frame.writeUInt16LE(frameData.length);
// add frame data
frame.writeBytes(frameData);
// add frame data
frame.writeBytes(frameData);
// write frame to device
await this.write(frame.toBytes());
}
async sendToRadioFrame(data) {
// write "app to radio" frame 0x3c "<"
this.emit("tx", data);
await this.writeFrame(0x3c, data);
}
// write frame to device
await this.write(frame.toBytes());
}
async sendToRadioFrame(data) {
// write "app to radio" frame 0x3c "<"
this.emit('tx', data);
await this.writeFrame(0x3c, data);
}
}
export default TCPConnection;

View file

@ -1,106 +1,109 @@
import Constants from "../constants.js";
import Connection from "./connection.js";
import Constants from '../constants.js';
import Connection from './connection.js';
class WebBleConnection extends Connection {
constructor(bleDevice) {
super();
this.bleDevice = bleDevice;
this.gattServer = null;
this.rxCharacteristic = null;
this.txCharacteristic = null;
this.init();
}
constructor(bleDevice) {
super();
this.bleDevice = bleDevice;
this.gattServer = null;
this.rxCharacteristic = null;
this.txCharacteristic = null;
this.init();
static async open() {
// ensure browser supports web bluetooth
if (!navigator.bluetooth) {
alert('Web Bluetooth is not supported in this browser');
return;
}
static async open() {
// ensure browser supports web bluetooth
if(!navigator.bluetooth){
alert("Web Bluetooth is not supported in this browser");
return;
}
// ask user to select device
const device = await navigator.bluetooth.requestDevice({
filters: [
{
services: [
Constants.Ble.ServiceUuid.toLowerCase(),
],
},
],
});
// make sure user selected a device
if(!device){
return null;
}
return new WebBleConnection(device);
// ask user to select device
const device = await navigator.bluetooth.requestDevice({
filters: [
{
services: [Constants.Ble.ServiceUuid.toLowerCase()],
},
],
});
// make sure user selected a device
if (!device) {
return null;
}
async init() {
return new WebBleConnection(device);
}
// listen for ble disconnect
this.bleDevice.addEventListener("gattserverdisconnected", () => {
this.onDisconnected();
});
async init() {
// listen for ble disconnect
this.bleDevice.addEventListener('gattserverdisconnected', () => {
this.onDisconnected();
});
// connect to gatt server
this.gattServer = await this.bleDevice.gatt.connect();
// connect to gatt server
this.gattServer = await this.bleDevice.gatt.connect();
// find service
const service = await this.gattServer.getPrimaryService(Constants.Ble.ServiceUuid.toLowerCase());
const characteristics = await service.getCharacteristics();
// find service
const service = await this.gattServer.getPrimaryService(
Constants.Ble.ServiceUuid.toLowerCase(),
);
const characteristics = await service.getCharacteristics();
// find rx characteristic (we write to this one, it's where the radio reads from)
this.rxCharacteristic = characteristics.find((characteristic) => {
return characteristic.uuid.toLowerCase() === Constants.Ble.CharacteristicUuidRx.toLowerCase();
});
// find rx characteristic (we write to this one, it's where the radio reads from)
this.rxCharacteristic = characteristics.find((characteristic) => {
return (
characteristic.uuid.toLowerCase() ===
Constants.Ble.CharacteristicUuidRx.toLowerCase()
);
});
// find tx characteristic (we read this one, it's where the radio writes to)
this.txCharacteristic = characteristics.find((characteristic) => {
return characteristic.uuid.toLowerCase() === Constants.Ble.CharacteristicUuidTx.toLowerCase();
});
// find tx characteristic (we read this one, it's where the radio writes to)
this.txCharacteristic = characteristics.find((characteristic) => {
return (
characteristic.uuid.toLowerCase() ===
Constants.Ble.CharacteristicUuidTx.toLowerCase()
);
});
// listen for frames from transmitted to us from the ble device
await this.txCharacteristic.startNotifications();
this.txCharacteristic.addEventListener('characteristicvaluechanged', (event) => {
const frame = new Uint8Array(event.target.value.buffer);
this.onFrameReceived(frame);
});
// listen for frames from transmitted to us from the ble device
await this.txCharacteristic.startNotifications();
this.txCharacteristic.addEventListener(
'characteristicvaluechanged',
(event) => {
const frame = new Uint8Array(event.target.value.buffer);
this.onFrameReceived(frame);
},
);
// fire connected event
await this.onConnected();
// fire connected event
await this.onConnected();
}
async close() {
try {
this.gattServer?.disconnect();
this.gattServer = null;
} catch (e) {
// ignore error when disconnecting
}
}
async close() {
try {
this.gattServer?.disconnect();
this.gattServer = null;
} catch(e) {
// ignore error when disconnecting
}
}
async write(bytes) {
try {
// fixme: NetworkError: GATT operation already in progress.
// todo: implement mutex to prevent multiple writes when another write is in progress
// we write to the rx characteristic, as that's where the radio reads from
await this.rxCharacteristic.writeValue(bytes);
} catch(e) {
console.log("failed to write to ble device", e);
}
}
async sendToRadioFrame(frame) {
this.emit("tx", frame);
await this.write(frame);
async write(bytes) {
try {
// fixme: NetworkError: GATT operation already in progress.
// todo: implement mutex to prevent multiple writes when another write is in progress
// we write to the rx characteristic, as that's where the radio reads from
await this.rxCharacteristic.writeValue(bytes);
} catch (e) {
console.log('failed to write to ble device', e);
}
}
async sendToRadioFrame(frame) {
this.emit('tx', frame);
await this.write(frame);
}
}
export default WebBleConnection;

View file

@ -1,105 +1,93 @@
import SerialConnection from "./serial_connection.js";
import SerialConnection from './serial_connection.js';
class WebSerialConnection extends SerialConnection {
constructor(serialPort) {
super();
constructor(serialPort) {
this.serialPort = serialPort;
this.reader = serialPort.readable.getReader();
this.writable = serialPort.writable;
this.readLoop();
super();
// listen for disconnect
this.serialPort.addEventListener('disconnect', () => {
this.onDisconnected();
});
this.serialPort = serialPort;
this.reader = serialPort.readable.getReader();
this.writable = serialPort.writable;
this.readLoop();
// listen for disconnect
this.serialPort.addEventListener("disconnect", () => {
this.onDisconnected();
});
// fire connected callback after constructor has returned
setTimeout(async () => {
await this.onConnected();
}, 0);
// fire connected callback after constructor has returned
setTimeout(async () => {
await this.onConnected();
}, 0);
}
static async open() {
// ensure browser supports web serial
if (!navigator.serial) {
alert('Web Serial is not supported in this browser');
return null;
}
static async open() {
// ask user to select device
const serialPort = await navigator.serial.requestPort({
filters: [],
});
// ensure browser supports web serial
if(!navigator.serial){
alert("Web Serial is not supported in this browser");
return null;
}
// open port
await serialPort.open({
baudRate: 115200,
});
// ask user to select device
const serialPort = await navigator.serial.requestPort({
filters: [],
});
// open port
await serialPort.open({
baudRate: 115200,
});
return new WebSerialConnection(serialPort);
return new WebSerialConnection(serialPort);
}
async close() {
// release reader lock
try {
this.reader.releaseLock();
} catch (e) {
// console.log("failed to release lock on serial port readable, ignoring...", e);
}
async close() {
// release reader lock
try {
this.reader.releaseLock();
} catch(e) {
// console.log("failed to release lock on serial port readable, ignoring...", e);
}
// close serial port
try {
await this.serialPort.close();
} catch(e) {
// console.log("failed to close serial port, ignoring...", e);
}
// close serial port
try {
await this.serialPort.close();
} catch (e) {
// console.log("failed to close serial port, ignoring...", e);
}
}
/* override */ async write(bytes) {
const writer = this.writable.getWriter();
try {
await writer.write(new Uint8Array(bytes));
} finally {
writer.releaseLock();
}
/* override */ async write(bytes) {
const writer = this.writable.getWriter();
try {
await writer.write(new Uint8Array(bytes));
} finally {
writer.releaseLock();
}
}
async readLoop() {
try {
while(true){
// read bytes until reader indicates it's done
const { value, done } = await this.reader.read();
if(done){
break;
}
// pass to super class handler
await this.onDataReceived(value);
}
} catch(error) {
// ignore error if reader was released
if(error instanceof TypeError){
return;
}
console.error('Error reading from serial port: ', error);
} finally {
this.reader.releaseLock();
async readLoop() {
try {
while (true) {
// read bytes until reader indicates it's done
const { value, done } = await this.reader.read();
if (done) {
break;
}
}
// pass to super class handler
await this.onDataReceived(value);
}
} catch (error) {
// ignore error if reader was released
if (error instanceof TypeError) {
return;
}
console.error('Error reading from serial port: ', error);
} finally {
this.reader.releaseLock();
}
}
}
export default WebSerialConnection;

View file

@ -1,131 +1,129 @@
class Constants {
static SupportedCompanionProtocolVersion = 1;
static SupportedCompanionProtocolVersion = 1;
static SerialFrameTypes = {
Incoming: 0x3e, // ">"
Outgoing: 0x3c, // "<"
};
static SerialFrameTypes = {
Incoming: 0x3e, // ">"
Outgoing: 0x3c, // "<"
}
static Ble = {
ServiceUuid: '6E400001-B5A3-F393-E0A9-E50E24DCCA9E',
CharacteristicUuidRx: '6E400002-B5A3-F393-E0A9-E50E24DCCA9E',
CharacteristicUuidTx: '6E400003-B5A3-F393-E0A9-E50E24DCCA9E',
};
static Ble = {
ServiceUuid: "6E400001-B5A3-F393-E0A9-E50E24DCCA9E",
CharacteristicUuidRx: "6E400002-B5A3-F393-E0A9-E50E24DCCA9E",
CharacteristicUuidTx: "6E400003-B5A3-F393-E0A9-E50E24DCCA9E",
}
static CommandCodes = {
AppStart: 1,
SendTxtMsg: 2,
SendChannelTxtMsg: 3,
GetContacts: 4,
GetDeviceTime: 5,
SetDeviceTime: 6,
SendSelfAdvert: 7,
SetAdvertName: 8,
AddUpdateContact: 9,
SyncNextMessage: 10,
SetRadioParams: 11,
SetTxPower: 12,
ResetPath: 13,
SetAdvertLatLon: 14,
RemoveContact: 15,
ShareContact: 16,
ExportContact: 17,
ImportContact: 18,
Reboot: 19,
GetBatteryVoltage: 20,
SetTuningParams: 21, // todo
DeviceQuery: 22,
ExportPrivateKey: 23,
ImportPrivateKey: 24,
SendRawData: 25,
SendLogin: 26, // todo
SendStatusReq: 27, // todo
GetChannel: 31,
SetChannel: 32,
SignStart: 33,
SignData: 34,
SignFinish: 35,
SendTracePath: 36,
// todo set device pin command
SetOtherParams: 38,
SendTelemetryReq: 39,
static CommandCodes = {
AppStart: 1,
SendTxtMsg: 2,
SendChannelTxtMsg: 3,
GetContacts: 4,
GetDeviceTime: 5,
SetDeviceTime: 6,
SendSelfAdvert: 7,
SetAdvertName: 8,
AddUpdateContact: 9,
SyncNextMessage: 10,
SetRadioParams: 11,
SetTxPower: 12,
ResetPath: 13,
SetAdvertLatLon: 14,
RemoveContact: 15,
ShareContact: 16,
ExportContact: 17,
ImportContact: 18,
Reboot: 19,
GetBatteryVoltage: 20,
SetTuningParams: 21, // todo
DeviceQuery: 22,
ExportPrivateKey: 23,
ImportPrivateKey: 24,
SendRawData: 25,
SendLogin: 26, // todo
SendStatusReq: 27, // todo
GetChannel: 31,
SetChannel: 32,
SignStart: 33,
SignData: 34,
SignFinish: 35,
SendTracePath: 36,
// todo set device pin command
SetOtherParams: 38,
SendTelemetryReq: 39,
SendBinaryReq: 50,
};
SendBinaryReq: 50,
}
static ResponseCodes = {
Ok: 0, // todo
Err: 1, // todo
ContactsStart: 2,
Contact: 3,
EndOfContacts: 4,
SelfInfo: 5,
Sent: 6,
ContactMsgRecv: 7,
ChannelMsgRecv: 8,
CurrTime: 9,
NoMoreMessages: 10,
ExportContact: 11,
BatteryVoltage: 12,
DeviceInfo: 13,
PrivateKey: 14,
Disabled: 15,
ChannelInfo: 18,
SignStart: 19,
Signature: 20,
};
static ResponseCodes = {
Ok: 0, // todo
Err: 1, // todo
ContactsStart: 2,
Contact: 3,
EndOfContacts: 4,
SelfInfo: 5,
Sent: 6,
ContactMsgRecv: 7,
ChannelMsgRecv: 8,
CurrTime: 9,
NoMoreMessages: 10,
ExportContact: 11,
BatteryVoltage: 12,
DeviceInfo: 13,
PrivateKey: 14,
Disabled: 15,
ChannelInfo: 18,
SignStart: 19,
Signature: 20,
}
static PushCodes = {
Advert: 0x80, // when companion is set to auto add contacts
PathUpdated: 0x81,
SendConfirmed: 0x82,
MsgWaiting: 0x83,
RawData: 0x84,
LoginSuccess: 0x85,
LoginFail: 0x86, // not usable yet
StatusResponse: 0x87,
LogRxData: 0x88,
TraceData: 0x89,
NewAdvert: 0x8a, // when companion is set to manually add contacts
TelemetryResponse: 0x8b,
BinaryResponse: 0x8c,
};
static PushCodes = {
Advert: 0x80, // when companion is set to auto add contacts
PathUpdated: 0x81,
SendConfirmed: 0x82,
MsgWaiting: 0x83,
RawData: 0x84,
LoginSuccess: 0x85,
LoginFail: 0x86, // not usable yet
StatusResponse: 0x87,
LogRxData: 0x88,
TraceData: 0x89,
NewAdvert: 0x8A, // when companion is set to manually add contacts
TelemetryResponse: 0x8B,
BinaryResponse: 0x8C,
}
static ErrorCodes = {
UnsupportedCmd: 1,
NotFound: 2,
TableFull: 3,
BadState: 4,
FileIoError: 5,
IllegalArg: 6,
};
static ErrorCodes = {
UnsupportedCmd: 1,
NotFound: 2,
TableFull: 3,
BadState: 4,
FileIoError: 5,
IllegalArg: 6,
}
static AdvType = {
None: 0,
Chat: 1,
Repeater: 2,
Room: 3,
};
static AdvType = {
None: 0,
Chat: 1,
Repeater: 2,
Room: 3,
}
static SelfAdvertTypes = {
ZeroHop: 0,
Flood: 1,
};
static SelfAdvertTypes = {
ZeroHop: 0,
Flood: 1,
}
static TxtTypes = {
Plain: 0,
CliData: 1,
SignedPlain: 2,
}
static BinaryRequestTypes = {
GetTelemetryData: 0x03, // #define REQ_TYPE_GET_TELEMETRY_DATA 0x03
GetAvgMinMax: 0x04, // #define REQ_TYPE_GET_AVG_MIN_MAX 0x04
GetAccessList: 0x05, // #define REQ_TYPE_GET_ACCESS_LIST 0x05
GetNeighbours: 0x06, // #define REQ_TYPE_GET_NEIGHBOURS 0x06
}
static TxtTypes = {
Plain: 0,
CliData: 1,
SignedPlain: 2,
};
static BinaryRequestTypes = {
GetTelemetryData: 0x03, // #define REQ_TYPE_GET_TELEMETRY_DATA 0x03
GetAvgMinMax: 0x04, // #define REQ_TYPE_GET_AVG_MIN_MAX 0x04
GetAccessList: 0x05, // #define REQ_TYPE_GET_ACCESS_LIST 0x05
GetNeighbours: 0x06, // #define REQ_TYPE_GET_NEIGHBOURS 0x06
};
}
export default Constants;

View file

@ -1,60 +1,50 @@
class EventEmitter {
constructor() {
this.eventListenersMap = new Map();
}
constructor() {
this.eventListenersMap = new Map();
on(event, callback) {
// create list of listeners for event if it doesn't exist
if (!this.eventListenersMap.has(event)) {
this.eventListenersMap.set(event, []);
}
on(event, callback) {
// create list of listeners for event if it doesn't exist
if(!this.eventListenersMap.has(event)){
this.eventListenersMap.set(event, []);
}
// add listener for event
this.eventListenersMap.get(event).push(callback);
// add listener for event
this.eventListenersMap.get(event).push(callback);
}
off(event, callback) {
// remove callback from listeners for this event
if (this.eventListenersMap.has(event)) {
const callbacks = this.eventListenersMap
.get(event)
.filter((cb) => cb !== callback);
this.eventListenersMap.set(event, callbacks);
}
}
off(event, callback) {
once(event, callback) {
// internal callback to handle the event
const internalCallback = (...data) => {
// we received an event, so lets remove the event listener
this.off(event, internalCallback);
// remove callback from listeners for this event
if(this.eventListenersMap.has(event)){
const callbacks = this.eventListenersMap.get(event).filter(cb => cb !== callback);
this.eventListenersMap.set(event, callbacks);
}
// fire the original callback provided by the user
setTimeout(() => callback(...data), 0);
};
// listen to this event
this.on(event, internalCallback);
}
emit(event, ...data) {
// invoke each listener for this event
if (this.eventListenersMap.has(event)) {
for (const eventListener of this.eventListenersMap.get(event)) {
setTimeout(() => eventListener(...data), 0);
}
}
once(event, callback) {
// internal callback to handle the event
const internalCallback = (...data) => {
// we received an event, so lets remove the event listener
this.off(event, internalCallback);
// fire the original callback provided by the user
setTimeout(() => callback(...data), 0);
};
// listen to this event
this.on(event, internalCallback);
}
emit(event, ...data) {
// invoke each listener for this event
if(this.eventListenersMap.has(event)){
for(const eventListener of this.eventListenersMap.get(event)){
setTimeout(() => eventListener(...data), 0);
}
}
}
}
}
export default EventEmitter;

View file

@ -1,25 +1,25 @@
import Connection from "./connection/connection.js";
import WebBleConnection from "./connection/web_ble_connection.js";
import SerialConnection from "./connection/serial_connection.js";
import NodeJSSerialConnection from "./connection/nodejs_serial_connection.js";
import WebSerialConnection from "./connection/web_serial_connection.js";
import TCPConnection from "./connection/tcp_connection.js";
import Constants from "./constants.js";
import Advert from "./advert.js";
import Packet from "./packet.js";
import BufferUtils from "./buffer_utils.js";
import CayenneLpp from "./cayenne_lpp.js";
import Connection from './connection/connection.js';
import WebBleConnection from './connection/web_ble_connection.js';
import SerialConnection from './connection/serial_connection.js';
import NodeJSSerialConnection from './connection/nodejs_serial_connection.js';
import WebSerialConnection from './connection/web_serial_connection.js';
import TCPConnection from './connection/tcp_connection.js';
import Constants from './constants.js';
import Advert from './advert.js';
import Packet from './packet.js';
import BufferUtils from './buffer_utils.js';
import CayenneLpp from './cayenne_lpp.js';
export {
Connection,
WebBleConnection,
SerialConnection,
NodeJSSerialConnection,
WebSerialConnection,
TCPConnection,
Constants,
Advert,
Packet,
BufferUtils,
CayenneLpp,
Connection,
WebBleConnection,
SerialConnection,
NodeJSSerialConnection,
WebSerialConnection,
TCPConnection,
Constants,
Advert,
Packet,
BufferUtils,
CayenneLpp,
};

View file

@ -1,215 +1,223 @@
import BufferReader from "./buffer_reader.js";
import Advert from "./advert.js";
import BufferReader from './buffer_reader.js';
import Advert from './advert.js';
class Packet {
// Packet::header values
static PH_ROUTE_MASK = 0x03; // 2-bits
static PH_TYPE_SHIFT = 2;
static PH_TYPE_MASK = 0x0f; // 4-bits
static PH_VER_SHIFT = 6;
static PH_VER_MASK = 0x03; // 2-bits
// Packet::header values
static PH_ROUTE_MASK = 0x03; // 2-bits
static PH_TYPE_SHIFT = 2;
static PH_TYPE_MASK = 0x0F; // 4-bits
static PH_VER_SHIFT = 6;
static PH_VER_MASK = 0x03; // 2-bits
static ROUTE_TYPE_RESERVED1 = 0x00; // FUTURE
static ROUTE_TYPE_FLOOD = 0x01; // flood mode, needs 'path' to be built up (max 64 bytes)
static ROUTE_TYPE_DIRECT = 0x02; // direct route, 'path' is supplied
static ROUTE_TYPE_RESERVED2 = 0x03; // FUTURE
static ROUTE_TYPE_RESERVED1 = 0x00; // FUTURE
static ROUTE_TYPE_FLOOD = 0x01; // flood mode, needs 'path' to be built up (max 64 bytes)
static ROUTE_TYPE_DIRECT = 0x02; // direct route, 'path' is supplied
static ROUTE_TYPE_RESERVED2 = 0x03; // FUTURE
static PAYLOAD_TYPE_REQ = 0x00; // request (prefixed with dest/src hashes, MAC) (enc data: timestamp, blob)
static PAYLOAD_TYPE_RESPONSE = 0x01; // response to REQ or ANON_REQ (prefixed with dest/src hashes, MAC) (enc data: timestamp, blob)
static PAYLOAD_TYPE_TXT_MSG = 0x02; // a plain text message (prefixed with dest/src hashes, MAC) (enc data: timestamp, text)
static PAYLOAD_TYPE_ACK = 0x03; // a simple ack
static PAYLOAD_TYPE_ADVERT = 0x04; // a node advertising its Identity
static PAYLOAD_TYPE_GRP_TXT = 0x05; // an (unverified) group text message (prefixed with channel hash, MAC) (enc data: timestamp, "name: msg")
static PAYLOAD_TYPE_GRP_DATA = 0x06; // an (unverified) group datagram (prefixed with channel hash, MAC) (enc data: timestamp, blob)
static PAYLOAD_TYPE_ANON_REQ = 0x07; // generic request (prefixed with dest_hash, ephemeral pub_key, MAC) (enc data: ...)
static PAYLOAD_TYPE_PATH = 0x08; // returned path (prefixed with dest/src hashes, MAC) (enc data: path, extra)
static PAYLOAD_TYPE_TRACE = 0x09; // trace a path, collecting SNR for each hop
static PAYLOAD_TYPE_RAW_CUSTOM = 0x0f; // custom packet as raw bytes, for applications with custom encryption, payloads, etc
static PAYLOAD_TYPE_REQ = 0x00; // request (prefixed with dest/src hashes, MAC) (enc data: timestamp, blob)
static PAYLOAD_TYPE_RESPONSE = 0x01; // response to REQ or ANON_REQ (prefixed with dest/src hashes, MAC) (enc data: timestamp, blob)
static PAYLOAD_TYPE_TXT_MSG = 0x02; // a plain text message (prefixed with dest/src hashes, MAC) (enc data: timestamp, text)
static PAYLOAD_TYPE_ACK = 0x03; // a simple ack
static PAYLOAD_TYPE_ADVERT = 0x04; // a node advertising its Identity
static PAYLOAD_TYPE_GRP_TXT = 0x05; // an (unverified) group text message (prefixed with channel hash, MAC) (enc data: timestamp, "name: msg")
static PAYLOAD_TYPE_GRP_DATA = 0x06; // an (unverified) group datagram (prefixed with channel hash, MAC) (enc data: timestamp, blob)
static PAYLOAD_TYPE_ANON_REQ = 0x07; // generic request (prefixed with dest_hash, ephemeral pub_key, MAC) (enc data: ...)
static PAYLOAD_TYPE_PATH = 0x08; // returned path (prefixed with dest/src hashes, MAC) (enc data: path, extra)
static PAYLOAD_TYPE_TRACE = 0x09; // trace a path, collecting SNR for each hop
static PAYLOAD_TYPE_RAW_CUSTOM = 0x0F; // custom packet as raw bytes, for applications with custom encryption, payloads, etc
constructor(header, path, payload) {
this.header = header;
this.path = path;
this.payload = payload;
constructor(header, path, payload) {
// parsed info
this.route_type = this.getRouteType();
this.route_type_string = this.getRouteTypeString();
this.payload_type = this.getPayloadType();
this.payload_type_string = this.getPayloadTypeString();
this.payload_version = this.getPayloadVer();
this.is_marked_do_not_retransmit = this.isMarkedDoNotRetransmit();
}
static fromBytes(bytes) {
const bufferReader = new BufferReader(bytes);
const header = bufferReader.readByte();
const pathLen = bufferReader.readInt8();
const path = bufferReader.readBytes(pathLen);
const payload = bufferReader.readRemainingBytes();
return new Packet(header, path, payload);
}
this.header = header;
this.path = path;
this.payload = payload;
// parsed info
this.route_type = this.getRouteType();
this.route_type_string = this.getRouteTypeString();
this.payload_type = this.getPayloadType();
this.payload_type_string = this.getPayloadTypeString();
this.payload_version = this.getPayloadVer();
this.is_marked_do_not_retransmit = this.isMarkedDoNotRetransmit();
getRouteType() {
return this.header & Packet.PH_ROUTE_MASK;
}
getRouteTypeString() {
switch (this.getRouteType()) {
case Packet.ROUTE_TYPE_FLOOD:
return 'FLOOD';
case Packet.ROUTE_TYPE_DIRECT:
return 'DIRECT';
default:
return null;
}
}
static fromBytes(bytes) {
const bufferReader = new BufferReader(bytes);
const header = bufferReader.readByte();
const pathLen = bufferReader.readInt8();
const path = bufferReader.readBytes(pathLen);
const payload = bufferReader.readRemainingBytes();
return new Packet(header, path, payload);
isRouteFlood() {
return this.getRouteType() === Packet.ROUTE_TYPE_FLOOD;
}
isRouteDirect() {
return this.getRouteType() === Packet.ROUTE_TYPE_DIRECT;
}
getPayloadType() {
return (this.header >> Packet.PH_TYPE_SHIFT) & Packet.PH_TYPE_MASK;
}
getPayloadTypeString() {
switch (this.getPayloadType()) {
case Packet.PAYLOAD_TYPE_REQ:
return 'REQ';
case Packet.PAYLOAD_TYPE_RESPONSE:
return 'RESPONSE';
case Packet.PAYLOAD_TYPE_TXT_MSG:
return 'TXT_MSG';
case Packet.PAYLOAD_TYPE_ACK:
return 'ACK';
case Packet.PAYLOAD_TYPE_ADVERT:
return 'ADVERT';
case Packet.PAYLOAD_TYPE_GRP_TXT:
return 'GRP_TXT';
case Packet.PAYLOAD_TYPE_GRP_DATA:
return 'GRP_DATA';
case Packet.PAYLOAD_TYPE_ANON_REQ:
return 'ANON_REQ';
case Packet.PAYLOAD_TYPE_PATH:
return 'PATH';
case Packet.PAYLOAD_TYPE_TRACE:
return 'TRACE';
case Packet.PAYLOAD_TYPE_RAW_CUSTOM:
return 'RAW_CUSTOM';
default:
return null;
}
}
getRouteType() {
return this.header & Packet.PH_ROUTE_MASK;
getPayloadVer() {
return (this.header >> Packet.PH_VER_SHIFT) & Packet.PH_VER_MASK;
}
markDoNotRetransmit() {
this.header = 0xff;
}
isMarkedDoNotRetransmit() {
return this.header === 0xff;
}
parsePayload() {
switch (this.getPayloadType()) {
case Packet.PAYLOAD_TYPE_PATH:
return this.parsePayloadTypePath();
case Packet.PAYLOAD_TYPE_REQ:
return this.parsePayloadTypeReq();
case Packet.PAYLOAD_TYPE_RESPONSE:
return this.parsePayloadTypeResponse();
case Packet.PAYLOAD_TYPE_TXT_MSG:
return this.parsePayloadTypeTxtMsg();
case Packet.PAYLOAD_TYPE_ACK:
return this.parsePayloadTypeAck();
case Packet.PAYLOAD_TYPE_ADVERT:
return this.parsePayloadTypeAdvert();
case Packet.PAYLOAD_TYPE_ANON_REQ:
return this.parsePayloadTypeAnonReq();
default:
return null;
}
}
getRouteTypeString() {
switch(this.getRouteType()){
case Packet.ROUTE_TYPE_FLOOD: return "FLOOD";
case Packet.ROUTE_TYPE_DIRECT: return "DIRECT";
default: return null;
}
}
parsePayloadTypePath() {
// parse bytes
const bufferReader = new BufferReader(this.payload);
const dest = bufferReader.readByte();
const src = bufferReader.readByte();
// todo other fields
isRouteFlood() {
return this.getRouteType() === Packet.ROUTE_TYPE_FLOOD;
}
return {
src: src,
dest: dest,
};
}
isRouteDirect() {
return this.getRouteType() === Packet.ROUTE_TYPE_DIRECT;
}
parsePayloadTypeReq() {
// parse bytes
const bufferReader = new BufferReader(this.payload);
const dest = bufferReader.readByte();
const src = bufferReader.readByte();
const encrypted = bufferReader.readRemainingBytes();
getPayloadType() {
return (this.header >> Packet.PH_TYPE_SHIFT) & Packet.PH_TYPE_MASK;
}
return {
src: src,
dest: dest,
encrypted: encrypted,
};
}
getPayloadTypeString() {
switch(this.getPayloadType()){
case Packet.PAYLOAD_TYPE_REQ: return "REQ";
case Packet.PAYLOAD_TYPE_RESPONSE: return "RESPONSE";
case Packet.PAYLOAD_TYPE_TXT_MSG: return "TXT_MSG";
case Packet.PAYLOAD_TYPE_ACK: return "ACK";
case Packet.PAYLOAD_TYPE_ADVERT: return "ADVERT";
case Packet.PAYLOAD_TYPE_GRP_TXT: return "GRP_TXT";
case Packet.PAYLOAD_TYPE_GRP_DATA: return "GRP_DATA";
case Packet.PAYLOAD_TYPE_ANON_REQ: return "ANON_REQ";
case Packet.PAYLOAD_TYPE_PATH: return "PATH";
case Packet.PAYLOAD_TYPE_TRACE: return "TRACE";
case Packet.PAYLOAD_TYPE_RAW_CUSTOM: return "RAW_CUSTOM";
default: return null;
}
}
parsePayloadTypeResponse() {
// parse bytes
const bufferReader = new BufferReader(this.payload);
const dest = bufferReader.readByte();
const src = bufferReader.readByte();
// todo other fields
getPayloadVer() {
return (this.header >> Packet.PH_VER_SHIFT) & Packet.PH_VER_MASK;
}
return {
src: src,
dest: dest,
};
}
markDoNotRetransmit() {
this.header = 0xFF;
}
parsePayloadTypeTxtMsg() {
// parse bytes
const bufferReader = new BufferReader(this.payload);
const dest = bufferReader.readByte();
const src = bufferReader.readByte();
// todo other fields
isMarkedDoNotRetransmit() {
return this.header === 0xFF;
}
return {
src: src,
dest: dest,
};
}
parsePayload() {
switch(this.getPayloadType()){
case Packet.PAYLOAD_TYPE_PATH: return this.parsePayloadTypePath();
case Packet.PAYLOAD_TYPE_REQ: return this.parsePayloadTypeReq();
case Packet.PAYLOAD_TYPE_RESPONSE: return this.parsePayloadTypeResponse();
case Packet.PAYLOAD_TYPE_TXT_MSG: return this.parsePayloadTypeTxtMsg();
case Packet.PAYLOAD_TYPE_ACK: return this.parsePayloadTypeAck();
case Packet.PAYLOAD_TYPE_ADVERT: return this.parsePayloadTypeAdvert();
case Packet.PAYLOAD_TYPE_ANON_REQ: return this.parsePayloadTypeAnonReq();
default: return null;
}
}
parsePayloadTypeAck() {
return {
ack_code: this.payload,
};
}
parsePayloadTypePath() {
parsePayloadTypeAdvert() {
const advert = Advert.fromBytes(this.payload);
return {
public_key: advert.publicKey,
timestamp: advert.timestamp,
app_data: advert.parseAppData(),
};
}
// parse bytes
const bufferReader = new BufferReader(this.payload);
const dest = bufferReader.readByte();
const src = bufferReader.readByte();
// todo other fields
return {
src: src,
dest: dest,
};
}
parsePayloadTypeReq() {
// parse bytes
const bufferReader = new BufferReader(this.payload);
const dest = bufferReader.readByte();
const src = bufferReader.readByte();
const encrypted = bufferReader.readRemainingBytes();
return {
src: src,
dest: dest,
encrypted: encrypted,
};
}
parsePayloadTypeResponse() {
// parse bytes
const bufferReader = new BufferReader(this.payload);
const dest = bufferReader.readByte();
const src = bufferReader.readByte();
// todo other fields
return {
src: src,
dest: dest,
};
}
parsePayloadTypeTxtMsg() {
// parse bytes
const bufferReader = new BufferReader(this.payload);
const dest = bufferReader.readByte();
const src = bufferReader.readByte();
// todo other fields
return {
src: src,
dest: dest,
};
}
parsePayloadTypeAck() {
return {
ack_code: this.payload,
};
}
parsePayloadTypeAdvert() {
const advert = Advert.fromBytes(this.payload);
return {
public_key: advert.publicKey,
timestamp: advert.timestamp,
app_data: advert.parseAppData(),
};
}
parsePayloadTypeAnonReq() {
// parse bytes
const bufferReader = new BufferReader(this.payload);
const dest = bufferReader.readByte();
const srcPublicKey = bufferReader.readBytes(32);
// todo other fields
return {
src: srcPublicKey,
dest: dest,
};
}
parsePayloadTypeAnonReq() {
// parse bytes
const bufferReader = new BufferReader(this.payload);
const dest = bufferReader.readByte();
const srcPublicKey = bufferReader.readBytes(32);
// todo other fields
return {
src: srcPublicKey,
dest: dest,
};
}
}
export default Packet;

View file

@ -1,11 +1,9 @@
class RandomUtils {
static getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
static getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
}
export default RandomUtils;