mirror of
https://github.com/liamcottle/reticulum-meshchat.git
synced 2026-04-28 00:20:48 +00:00
update rnode flasher
This commit is contained in:
parent
eaf1b75c54
commit
6f321741d7
2 changed files with 413 additions and 294 deletions
|
|
@ -110,7 +110,7 @@
|
|||
<div class="border-t px-2 py-1 text-sm">
|
||||
<div>
|
||||
<span>Download Firmware</span>
|
||||
<span v-if="selectedProduct && selectedModel && recommendedFirmwareFilename">: {{ recommendedFirmwareFilename }}</span>
|
||||
<span v-if="selectedProduct && selectedModel && recommendedFirmwareFilename">: <a target="_blank" :href="`https://github.com/markqvist/RNode_Firmware/releases/latest/download/${recommendedFirmwareFilename}`" class="text-blue-500 hover:underline">{{ recommendedFirmwareFilename }}</a></span>
|
||||
</div>
|
||||
<div class="space-x-1">
|
||||
<a target="_blank" href="https://github.com/markqvist/RNode_Firmware/releases" class="text-blue-500 hover:underline">Official Firmware</a>
|
||||
|
|
@ -312,6 +312,48 @@
|
|||
|
||||
</div>
|
||||
|
||||
<div class="border bg-gray-50 rounded shadow">
|
||||
|
||||
<div class="border-b px-2 py-1">
|
||||
Configure Display (optional)
|
||||
</div>
|
||||
|
||||
<div class="p-3 space-y-2">
|
||||
|
||||
<div class="flex space-x-1">
|
||||
<div class="my-auto">Rotation</div>
|
||||
<button @click="setDisplayRotation(0)" class="border border-gray-500 px-2 bg-gray-100 hover:bg-gray-200 rounded">
|
||||
0
|
||||
</button>
|
||||
<button @click="setDisplayRotation(1)" class="border border-gray-500 px-2 bg-gray-100 hover:bg-gray-200 rounded">
|
||||
1
|
||||
</button>
|
||||
<button @click="setDisplayRotation(2)" class="border border-gray-500 px-2 bg-gray-100 hover:bg-gray-200 rounded">
|
||||
2
|
||||
</button>
|
||||
<button @click="setDisplayRotation(3)" class="border border-gray-500 px-2 bg-gray-100 hover:bg-gray-200 rounded">
|
||||
3
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex space-x-1">
|
||||
<div class="my-auto">Reconditioning</div>
|
||||
<button @click="startDisplayReconditioning" class="border border-gray-500 px-2 bg-gray-100 hover:bg-gray-200 rounded">
|
||||
Start
|
||||
</button>
|
||||
<button @click="reboot" class="border border-gray-500 px-2 bg-gray-100 hover:bg-gray-200 rounded">
|
||||
Stop
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="border-t px-2 py-1 text-sm">
|
||||
<div>Setting display rotation requires firmware v1.80+</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- setup web-serial-polyfill -->
|
||||
|
|
@ -334,6 +376,8 @@
|
|||
data() {
|
||||
return {
|
||||
|
||||
rnode: null,
|
||||
|
||||
isFlashing: false,
|
||||
flashingProgress: 0,
|
||||
|
||||
|
|
@ -397,6 +441,22 @@
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Heltec T114",
|
||||
id: ROM.PRODUCT_HELTEC_T114,
|
||||
platform: ROM.PLATFORM_NRF52,
|
||||
models: [
|
||||
{
|
||||
id: ROM.MODEL_C6,
|
||||
name: "470-510 MHz (HT-n5262-LF)",
|
||||
},
|
||||
{
|
||||
id: ROM.MODEL_C7,
|
||||
name: "863-928 MHz (HT-n5262-HF)",
|
||||
},
|
||||
],
|
||||
firmware_filename: "rnode_firmware_heltec_t114.zip",
|
||||
},
|
||||
{
|
||||
name: "LilyGO LoRa32 v1.0",
|
||||
id: ROM.PRODUCT_T32_10,
|
||||
|
|
@ -587,6 +647,21 @@
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: ROM.MODEL_AC,
|
||||
name: "2.4 GHz (with SX1280 chip)",
|
||||
firmware_filename: "rnode_firmware_t3s3_sx1280_pa.zip",
|
||||
flash_config: {
|
||||
flash_size: "4MB",
|
||||
flash_files: {
|
||||
"0xe000": "rnode_firmware_t3s3_sx1280_pa.boot_app0",
|
||||
"0x0": "rnode_firmware_t3s3_sx1280_pa.bootloader",
|
||||
"0x10000": "rnode_firmware_t3s3_sx1280_pa.bin",
|
||||
"0x210000": "console_image.bin",
|
||||
"0x8000": "rnode_firmware_t3s3_sx1280_pa.partitions",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
@ -714,11 +789,11 @@
|
|||
platform: ROM.PLATFORM_NRF52,
|
||||
models: [
|
||||
{
|
||||
id: ROM.MODEL_T4,
|
||||
id: ROM.MODEL_16,
|
||||
name: "433 MHz",
|
||||
},
|
||||
{
|
||||
id: ROM.MODEL_T9,
|
||||
id: ROM.MODEL_17,
|
||||
name: "868 MHz / 915 MHz / 923 MHz",
|
||||
},
|
||||
],
|
||||
|
|
@ -858,11 +933,37 @@
|
|||
return null;
|
||||
}
|
||||
|
||||
// close any existing rnode connection
|
||||
if(this.rnode){
|
||||
await this.rnode.close();
|
||||
this.rnode = null;
|
||||
}
|
||||
|
||||
// ask user to select device
|
||||
return await navigator.serial.requestPort({
|
||||
filters: [],
|
||||
});
|
||||
|
||||
},
|
||||
async askForRNode() {
|
||||
|
||||
// ask for serial port
|
||||
const serialPort = await this.askForSerialPort();
|
||||
if(!serialPort){
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if device is an rnode
|
||||
this.rnode = await RNode.fromSerialPort(serialPort);
|
||||
const isRNode = await this.rnode.detect();
|
||||
if(!isRNode){
|
||||
await this.rnode.close();
|
||||
alert("Selected device is not an RNode!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.rnode;
|
||||
|
||||
},
|
||||
async enterDfuMode() {
|
||||
|
||||
|
|
@ -1069,17 +1170,9 @@
|
|||
},
|
||||
async detect() {
|
||||
|
||||
// ask for serial port
|
||||
const serialPort = await this.askForSerialPort();
|
||||
if(!serialPort){
|
||||
return;
|
||||
}
|
||||
|
||||
// check if device is an rnode
|
||||
const rnode = await RNode.fromSerialPort(serialPort);
|
||||
const isRNode = await rnode.detect();
|
||||
if(!isRNode){
|
||||
alert("Selected device is not an RNode!");
|
||||
// ask for rnode
|
||||
const rnode = await this.askForRNode();
|
||||
if(!rnode){
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1122,17 +1215,9 @@
|
|||
},
|
||||
async reboot() {
|
||||
|
||||
// ask for serial port
|
||||
const serialPort = await this.askForSerialPort();
|
||||
if(!serialPort){
|
||||
return;
|
||||
}
|
||||
|
||||
// check if device is an rnode
|
||||
const rnode = await RNode.fromSerialPort(serialPort);
|
||||
const isRNode = await rnode.detect();
|
||||
if(!isRNode){
|
||||
alert("Selected device is not an RNode!");
|
||||
// ask for rnode
|
||||
const rnode = await this.askForRNode();
|
||||
if(!rnode){
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1210,17 +1295,9 @@
|
|||
},
|
||||
async readDisplay() {
|
||||
|
||||
// ask for serial port
|
||||
const serialPort = await this.askForSerialPort();
|
||||
if(!serialPort){
|
||||
return;
|
||||
}
|
||||
|
||||
// check if device is an rnode
|
||||
const rnode = await RNode.fromSerialPort(serialPort);
|
||||
const isRNode = await rnode.detect();
|
||||
if(!isRNode){
|
||||
alert("Selected device is not an RNode!");
|
||||
// ask for rnode
|
||||
const rnode = await this.askForRNode();
|
||||
if(!rnode){
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1236,17 +1313,9 @@
|
|||
},
|
||||
async dumpEeprom() {
|
||||
|
||||
// ask for serial port
|
||||
const serialPort = await this.askForSerialPort();
|
||||
if(!serialPort){
|
||||
return;
|
||||
}
|
||||
|
||||
// check if device is an rnode
|
||||
const rnode = await RNode.fromSerialPort(serialPort);
|
||||
const isRNode = await rnode.detect();
|
||||
if(!isRNode){
|
||||
alert("Selected device is not an RNode!");
|
||||
// ask for rnode
|
||||
const rnode = await this.askForRNode();
|
||||
if(!rnode){
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1264,22 +1333,15 @@
|
|||
},
|
||||
async wipeEeprom() {
|
||||
|
||||
// ask for serial port
|
||||
const serialPort = await this.askForSerialPort();
|
||||
if(!serialPort){
|
||||
// ask for rnode
|
||||
const rnode = await this.askForRNode();
|
||||
if(!rnode){
|
||||
return;
|
||||
}
|
||||
|
||||
// ask user to confirm
|
||||
if(!confirm("Are you sure you want to wipe the eeprom on this device? This will take about 30 seconds. An alert will show when the eeprom wipe has finished.")){
|
||||
return;
|
||||
}
|
||||
|
||||
// check if device is an rnode
|
||||
const rnode = await RNode.fromSerialPort(serialPort);
|
||||
const isRNode = await rnode.detect();
|
||||
if(!isRNode){
|
||||
alert("Selected device is not an RNode!");
|
||||
await rnode.close();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1298,18 +1360,9 @@
|
|||
},
|
||||
async provision() {
|
||||
|
||||
// ask for serial port
|
||||
const serialPort = await this.askForSerialPort();
|
||||
if(!serialPort){
|
||||
return;
|
||||
}
|
||||
|
||||
// check if device is an rnode
|
||||
const rnode = await RNode.fromSerialPort(serialPort);
|
||||
const isRNode = await rnode.detect();
|
||||
if(!isRNode){
|
||||
alert("Selected device is not an RNode!");
|
||||
await rnode.close();
|
||||
// ask for rnode
|
||||
const rnode = await this.askForRNode();
|
||||
if(!rnode){
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1489,17 +1542,9 @@
|
|||
},
|
||||
async setFirmwareHash() {
|
||||
|
||||
// ask for serial port
|
||||
const serialPort = await this.askForSerialPort();
|
||||
if(!serialPort){
|
||||
return;
|
||||
}
|
||||
|
||||
// check if device is an rnode
|
||||
const rnode = await RNode.fromSerialPort(serialPort);
|
||||
const isRNode = await rnode.detect();
|
||||
if(!isRNode){
|
||||
alert("Selected device is not an RNode!");
|
||||
// ask for rnode
|
||||
const rnode = await this.askForRNode();
|
||||
if(!rnode){
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1546,17 +1591,9 @@
|
|||
},
|
||||
async enableTncMode() {
|
||||
|
||||
// ask for serial port
|
||||
const serialPort = await this.askForSerialPort();
|
||||
if(!serialPort){
|
||||
return;
|
||||
}
|
||||
|
||||
// check if device is an rnode
|
||||
const rnode = await RNode.fromSerialPort(serialPort);
|
||||
const isRNode = await rnode.detect();
|
||||
if(!isRNode){
|
||||
alert("Selected device is not an RNode!");
|
||||
// ask for rnode
|
||||
const rnode = await this.askForRNode();
|
||||
if(!rnode){
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1602,17 +1639,9 @@
|
|||
},
|
||||
async disableTncMode() {
|
||||
|
||||
// ask for serial port
|
||||
const serialPort = await this.askForSerialPort();
|
||||
if(!serialPort){
|
||||
return;
|
||||
}
|
||||
|
||||
// check if device is an rnode
|
||||
const rnode = await RNode.fromSerialPort(serialPort);
|
||||
const isRNode = await rnode.detect();
|
||||
if(!isRNode){
|
||||
alert("Selected device is not an RNode!");
|
||||
// ask for rnode
|
||||
const rnode = await this.askForRNode();
|
||||
if(!rnode){
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1643,17 +1672,9 @@
|
|||
},
|
||||
async enableBluetooth() {
|
||||
|
||||
// ask for serial port
|
||||
const serialPort = await this.askForSerialPort();
|
||||
if(!serialPort){
|
||||
return;
|
||||
}
|
||||
|
||||
// check if device is an rnode
|
||||
const rnode = await RNode.fromSerialPort(serialPort);
|
||||
const isRNode = await rnode.detect();
|
||||
if(!isRNode){
|
||||
alert("Selected device is not an RNode!");
|
||||
// ask for rnode
|
||||
const rnode = await this.askForRNode();
|
||||
if(!rnode){
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1671,26 +1692,18 @@
|
|||
await rnode.enableBluetooth();
|
||||
console.log("enabling bluetooth: done");
|
||||
|
||||
await Utils.sleepMillis(1000);
|
||||
alert("Bluetooth has been enabled!");
|
||||
|
||||
// done
|
||||
await Utils.sleepMillis(1000);
|
||||
await rnode.close();
|
||||
alert("Bluetooth has been enabled!");
|
||||
|
||||
},
|
||||
async disableBluetooth() {
|
||||
|
||||
// ask for serial port
|
||||
const serialPort = await this.askForSerialPort();
|
||||
if(!serialPort){
|
||||
return;
|
||||
}
|
||||
|
||||
// check if device is an rnode
|
||||
const rnode = await RNode.fromSerialPort(serialPort);
|
||||
const isRNode = await rnode.detect();
|
||||
if(!isRNode){
|
||||
alert("Selected device is not an RNode!");
|
||||
// ask for rnode
|
||||
const rnode = await this.askForRNode();
|
||||
if(!rnode){
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1707,27 +1720,18 @@
|
|||
console.log("disabling bluetooth");
|
||||
await rnode.disableBluetooth();
|
||||
console.log("disabling bluetooth: done");
|
||||
|
||||
await Utils.sleepMillis(1000);
|
||||
alert("Bluetooth has been disabled!");
|
||||
|
||||
// done
|
||||
await Utils.sleepMillis(1000);
|
||||
await rnode.close();
|
||||
alert("Bluetooth has been disabled!");
|
||||
|
||||
},
|
||||
async startBluetoothPairing() {
|
||||
|
||||
// ask for serial port
|
||||
const serialPort = await this.askForSerialPort();
|
||||
if(!serialPort){
|
||||
return;
|
||||
}
|
||||
|
||||
// check if device is an rnode
|
||||
const rnode = await RNode.fromSerialPort(serialPort);
|
||||
const isRNode = await rnode.detect();
|
||||
if(!isRNode){
|
||||
alert("Selected device is not an RNode!");
|
||||
// ask for rnode
|
||||
const rnode = await this.askForRNode();
|
||||
if(!rnode){
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1743,13 +1747,72 @@
|
|||
// start bluetooth pairing
|
||||
try {
|
||||
console.log("start bluetooth pairing");
|
||||
const pin = await rnode.startBluetoothPairing();
|
||||
await rnode.startBluetoothPairing(async (pin) => {
|
||||
alert("Bluetooth Pairing Pin: " + pin);
|
||||
await rnode.close();
|
||||
});
|
||||
console.log("start bluetooth pairing: done");
|
||||
} catch(error) {
|
||||
alert(error);
|
||||
}
|
||||
|
||||
alert("RNode should now be in Bluetooth Pairing mode. A pin will be shown on the screen when you pair with it from Android bluetooth settings.");
|
||||
// tell user device is in pairing mode, and how to pair
|
||||
alert([
|
||||
"- RNode is in Bluetooth Pairing Mode for 30 seconds.",
|
||||
"- Close this alert before performing the next steps.",
|
||||
"- Open bluetooth settings on your Android device.",
|
||||
"- Click pair on the RNode device that shows up.",
|
||||
"- Bluetooth pin will shown on your RNode screen and on this page.",
|
||||
].join("\n"));
|
||||
|
||||
},
|
||||
async setDisplayRotation(rotation) {
|
||||
|
||||
// ask for rnode
|
||||
const rnode = await this.askForRNode();
|
||||
if(!rnode){
|
||||
return;
|
||||
}
|
||||
|
||||
// check if device has been provisioned
|
||||
const rom = await rnode.getRomAsObject();
|
||||
const details = rom.parse();
|
||||
if(!details || !details.is_provisioned){
|
||||
alert("Eeprom is not provisioned. You must do this first!");
|
||||
await rnode.close();
|
||||
return;
|
||||
}
|
||||
|
||||
// configure
|
||||
console.log("setting display rotation");
|
||||
await rnode.setDisplayRotation(rotation);
|
||||
console.log("setting display rotation: done");
|
||||
|
||||
// done
|
||||
await rnode.close();
|
||||
|
||||
},
|
||||
async startDisplayReconditioning() {
|
||||
|
||||
// ask for rnode
|
||||
const rnode = await this.askForRNode();
|
||||
if(!rnode){
|
||||
return;
|
||||
}
|
||||
|
||||
// check if device has been provisioned
|
||||
const rom = await rnode.getRomAsObject();
|
||||
const details = rom.parse();
|
||||
if(!details || !details.is_provisioned){
|
||||
alert("Eeprom is not provisioned. You must do this first!");
|
||||
await rnode.close();
|
||||
return;
|
||||
}
|
||||
|
||||
// configure
|
||||
console.log("starting display reconditioning");
|
||||
await rnode.startDisplayReconditioning();
|
||||
console.log("starting display reconditioning: done");
|
||||
|
||||
// done
|
||||
await rnode.close();
|
||||
|
|
|
|||
|
|
@ -79,6 +79,8 @@ class RNode {
|
|||
ROM_UNLOCK_BYTE = 0xF8;
|
||||
CMD_HASHES = 0x60;
|
||||
CMD_FW_UPD = 0x61;
|
||||
CMD_DISP_ROT = 0x67;
|
||||
CMD_DISP_RCND = 0x68;
|
||||
|
||||
CMD_BT_CTRL = 0x46;
|
||||
CMD_BT_PIN = 0x62;
|
||||
|
|
@ -121,8 +123,10 @@ class RNode {
|
|||
|
||||
constructor(serialPort) {
|
||||
this.serialPort = serialPort;
|
||||
this.readable = serialPort.readable;
|
||||
this.reader = serialPort.readable.getReader();
|
||||
this.writable = serialPort.writable;
|
||||
this.callbacks = {};
|
||||
this.readLoop();
|
||||
}
|
||||
|
||||
static async fromSerialPort(serialPort) {
|
||||
|
|
@ -137,11 +141,21 @@ class RNode {
|
|||
}
|
||||
|
||||
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);
|
||||
//console.log("failed to close serial port, ignoring...", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async write(bytes) {
|
||||
|
|
@ -153,79 +167,100 @@ class RNode {
|
|||
}
|
||||
}
|
||||
|
||||
async readFromSerialPort(timeoutMillis) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
async readLoop() {
|
||||
try {
|
||||
let buffer = [];
|
||||
let inFrame = false;
|
||||
while(true){
|
||||
|
||||
// create reader
|
||||
const reader = this.readable.getReader();
|
||||
// read kiss frames until reader indicates it's done
|
||||
const { value, done } = await this.reader.read();
|
||||
if(done){
|
||||
break;
|
||||
}
|
||||
|
||||
// timeout after provided millis
|
||||
if(timeoutMillis != null){
|
||||
setTimeout(() => {
|
||||
reader.releaseLock();
|
||||
reject("timeout");
|
||||
}, timeoutMillis);
|
||||
}
|
||||
|
||||
// attempt to read kiss frame
|
||||
try {
|
||||
let buffer = [];
|
||||
while(true){
|
||||
const { value, done } = await reader.read();
|
||||
if(done){
|
||||
break;
|
||||
}
|
||||
if(value){
|
||||
for(let byte of value){
|
||||
buffer.push(byte);
|
||||
if(byte === this.KISS_FEND){
|
||||
if(buffer.length > 1){
|
||||
resolve(this.handleKISSFrame(buffer));
|
||||
return;
|
||||
}
|
||||
buffer = [this.KISS_FEND]; // Start new frame
|
||||
// read kiss frames
|
||||
for(const byte of value){
|
||||
if(byte === this.KISS_FEND){
|
||||
if(inFrame){
|
||||
// End of frame
|
||||
const decodedFrame = this.decodeKissFrame(buffer);
|
||||
if(decodedFrame){
|
||||
this.onCommandReceived(decodedFrame);
|
||||
} else {
|
||||
console.warn("Invalid frame ignored.");
|
||||
}
|
||||
buffer = [];
|
||||
}
|
||||
inFrame = !inFrame;
|
||||
} else if(inFrame) {
|
||||
buffer.push(byte);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error reading from serial port: ', error);
|
||||
} finally {
|
||||
reader.releaseLock();
|
||||
|
||||
}
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
|
||||
handleKISSFrame(frame) {
|
||||
onCommandReceived(data) {
|
||||
try {
|
||||
|
||||
let data = [];
|
||||
// get received command and bytes from data
|
||||
const [ command, ...bytes ] = data;
|
||||
console.log("onCommandReceived", "0x" + command.toString(16), bytes);
|
||||
|
||||
// find callback for received command
|
||||
const callback = this.callbacks[command];
|
||||
if(!callback){
|
||||
return;
|
||||
}
|
||||
|
||||
// fire callback
|
||||
callback(bytes);
|
||||
|
||||
// forget callback
|
||||
delete this.callbacks[command];
|
||||
|
||||
} catch(e) {
|
||||
console.log("failed to handle received command", data, e);
|
||||
}
|
||||
}
|
||||
|
||||
decodeKissFrame(frame) {
|
||||
|
||||
const data = [];
|
||||
let escaping = false;
|
||||
|
||||
// Skip the initial 0xC0 and process the rest
|
||||
for(let i = 1; i < frame.length; i++){
|
||||
let byte = frame[i];
|
||||
if (escaping) {
|
||||
if (byte === this.KISS_TFEND) {
|
||||
for(const byte of frame){
|
||||
if(escaping){
|
||||
if(byte === this.KISS_TFEND){
|
||||
data.push(this.KISS_FEND);
|
||||
} else if (byte === this.KISS_TFESC) {
|
||||
} else if(byte === this.KISS_TFESC) {
|
||||
data.push(this.KISS_FESC);
|
||||
} else {
|
||||
return null; // Invalid escape sequence
|
||||
}
|
||||
escaping = false;
|
||||
} else if(byte === this.KISS_FESC) {
|
||||
escaping = true;
|
||||
} else {
|
||||
if (byte === this.KISS_FESC) {
|
||||
escaping = true;
|
||||
} else if (byte === this.KISS_FEND) {
|
||||
// Ignore the end frame delimiter
|
||||
break;
|
||||
} else {
|
||||
data.push(byte);
|
||||
}
|
||||
data.push(byte);
|
||||
}
|
||||
}
|
||||
|
||||
//console.log('Received KISS frame data:', new Uint8Array(data));
|
||||
return data;
|
||||
// return null if incomplete escape at end
|
||||
return escaping ? null : data;
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -248,6 +283,28 @@ class RNode {
|
|||
await this.write(this.createKissFrame(data));
|
||||
}
|
||||
|
||||
// sends a command to the rnode, and resolves the promise with the result
|
||||
async sendCommand(command, data) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
|
||||
// listen for response
|
||||
this.callbacks[command] = (response) => {
|
||||
resolve(response);
|
||||
};
|
||||
|
||||
// send command
|
||||
await this.sendKissCommand([
|
||||
command,
|
||||
...data,
|
||||
]);
|
||||
|
||||
} catch(e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async reset() {
|
||||
await this.sendKissCommand([
|
||||
this.CMD_RESET,
|
||||
|
|
@ -256,30 +313,42 @@ class RNode {
|
|||
}
|
||||
|
||||
async detect() {
|
||||
return new Promise(async (resolve) => {
|
||||
try {
|
||||
|
||||
// ask if device is rnode
|
||||
await this.sendKissCommand([
|
||||
this.CMD_DETECT,
|
||||
this.DETECT_REQ,
|
||||
]);
|
||||
// timeout after provided millis
|
||||
const timeout = setTimeout(() => {
|
||||
resolve(false);
|
||||
}, 2000);
|
||||
|
||||
// read response from device
|
||||
const [ command, responseByte ] = await this.readFromSerialPort();
|
||||
// detect rnode
|
||||
const response = await this.sendCommand(this.CMD_DETECT, [
|
||||
this.DETECT_REQ,
|
||||
]);
|
||||
|
||||
// device is an rnode if response is as expected
|
||||
return command === this.CMD_DETECT && responseByte === this.DETECT_RESP;
|
||||
// we no longer want to timeout
|
||||
clearTimeout(timeout);
|
||||
|
||||
// device is an rnode if response is as expected
|
||||
const [ responseByte ] = response;
|
||||
const isRnode = responseByte === this.DETECT_RESP;
|
||||
resolve(isRnode);
|
||||
|
||||
} catch(e) {
|
||||
resolve(false);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
async getFirmwareVersion() {
|
||||
|
||||
await this.sendKissCommand([
|
||||
this.CMD_FW_VERSION,
|
||||
const response = await this.sendCommand(this.CMD_FW_VERSION, [
|
||||
0x00,
|
||||
]);
|
||||
|
||||
// read response from device
|
||||
var [ command, majorVersion, minorVersion ] = await this.readFromSerialPort();
|
||||
var [ majorVersion, minorVersion ] = response;
|
||||
if(minorVersion.length === 1){
|
||||
minorVersion = "0" + minorVersion;
|
||||
}
|
||||
|
|
@ -291,99 +360,91 @@ class RNode {
|
|||
|
||||
async getPlatform() {
|
||||
|
||||
await this.sendKissCommand([
|
||||
this.CMD_PLATFORM,
|
||||
const response = await this.sendCommand(this.CMD_PLATFORM, [
|
||||
0x00,
|
||||
]);
|
||||
|
||||
// read response from device
|
||||
const [ command, platformByte ] = await this.readFromSerialPort();
|
||||
const [ platformByte ] = response;
|
||||
return platformByte;
|
||||
|
||||
}
|
||||
|
||||
async getMcu() {
|
||||
|
||||
await this.sendKissCommand([
|
||||
this.CMD_MCU,
|
||||
const response = await this.sendCommand(this.CMD_MCU, [
|
||||
0x00,
|
||||
]);
|
||||
|
||||
// read response from device
|
||||
const [ command, mcuByte ] = await this.readFromSerialPort();
|
||||
const [ mcuByte ] = response;
|
||||
return mcuByte;
|
||||
|
||||
}
|
||||
|
||||
async getBoard() {
|
||||
|
||||
await this.sendKissCommand([
|
||||
this.CMD_BOARD,
|
||||
const response = await this.sendCommand(this.CMD_BOARD, [
|
||||
0x00,
|
||||
]);
|
||||
|
||||
// read response from device
|
||||
const [ command, boardByte ] = await this.readFromSerialPort();
|
||||
const [ boardByte ] = response;
|
||||
return boardByte;
|
||||
|
||||
}
|
||||
|
||||
async getDeviceHash() {
|
||||
|
||||
await this.sendKissCommand([
|
||||
this.CMD_DEV_HASH,
|
||||
const response = await this.sendCommand(this.CMD_DEV_HASH, [
|
||||
0x01, // anything != 0x00
|
||||
]);
|
||||
|
||||
// read response from device
|
||||
const [ command, ...deviceHash ] = await this.readFromSerialPort();
|
||||
const [ ...deviceHash ] = response;
|
||||
return deviceHash;
|
||||
|
||||
}
|
||||
|
||||
async getTargetFirmwareHash() {
|
||||
|
||||
await this.sendKissCommand([
|
||||
this.CMD_HASHES,
|
||||
const response = await this.sendCommand(this.CMD_HASHES, [
|
||||
this.HASH_TYPE_TARGET_FIRMWARE,
|
||||
]);
|
||||
|
||||
// read response from device
|
||||
const [ command, hashType, ...targetFirmwareHash ] = await this.readFromSerialPort();
|
||||
const [ hashType, ...targetFirmwareHash ] = response;
|
||||
return targetFirmwareHash;
|
||||
|
||||
}
|
||||
|
||||
async getFirmwareHash() {
|
||||
|
||||
await this.sendKissCommand([
|
||||
this.CMD_HASHES,
|
||||
const response = await this.sendCommand(this.CMD_HASHES, [
|
||||
this.HASH_TYPE_FIRMWARE,
|
||||
]);
|
||||
|
||||
// read response from device
|
||||
const [ command, hashType, ...firmwareHash ] = await this.readFromSerialPort();
|
||||
const [ hashType, ...firmwareHash ] = response;
|
||||
return firmwareHash;
|
||||
|
||||
}
|
||||
|
||||
async getRom() {
|
||||
|
||||
await this.sendKissCommand([
|
||||
this.CMD_ROM_READ,
|
||||
const response = await this.sendCommand(this.CMD_ROM_READ, [
|
||||
0x00,
|
||||
]);
|
||||
|
||||
// read response from device
|
||||
const [ command, ...eepromBytes ] = await this.readFromSerialPort();
|
||||
const [ ...eepromBytes ] = response;
|
||||
return eepromBytes;
|
||||
|
||||
}
|
||||
|
||||
async getFrequency() {
|
||||
|
||||
await this.sendKissCommand([
|
||||
this.CMD_FREQUENCY,
|
||||
const response = await this.sendCommand(this.CMD_FREQUENCY, [
|
||||
// request frequency by sending zero as 4 bytes
|
||||
0x00,
|
||||
0x00,
|
||||
|
|
@ -392,7 +453,7 @@ class RNode {
|
|||
]);
|
||||
|
||||
// read response from device
|
||||
const [ command, ...frequencyBytes ] = await this.readFromSerialPort();
|
||||
const [ ...frequencyBytes ] = response;
|
||||
|
||||
// convert 4 bytes to 32bit integer representing frequency in hertz
|
||||
const frequencyInHz = frequencyBytes[0] << 24 | frequencyBytes[1] << 16 | frequencyBytes[2] << 8 | frequencyBytes[3];
|
||||
|
|
@ -402,8 +463,7 @@ class RNode {
|
|||
|
||||
async getBandwidth() {
|
||||
|
||||
await this.sendKissCommand([
|
||||
this.CMD_BANDWIDTH,
|
||||
const response = await this.sendCommand(this.CMD_BANDWIDTH, [
|
||||
// request bandwidth by sending zero as 4 bytes
|
||||
0x00,
|
||||
0x00,
|
||||
|
|
@ -412,7 +472,7 @@ class RNode {
|
|||
]);
|
||||
|
||||
// read response from device
|
||||
const [ command, ...bandwidthBytes ] = await this.readFromSerialPort();
|
||||
const [ ...bandwidthBytes ] = response;
|
||||
|
||||
// convert 4 bytes to 32bit integer representing bandwidth in hertz
|
||||
const bandwidthInHz = bandwidthBytes[0] << 24 | bandwidthBytes[1] << 16 | bandwidthBytes[2] << 8 | bandwidthBytes[3];
|
||||
|
|
@ -422,69 +482,60 @@ class RNode {
|
|||
|
||||
async getTxPower() {
|
||||
|
||||
await this.sendKissCommand([
|
||||
this.CMD_TXPOWER,
|
||||
const response = await this.sendCommand(this.CMD_TXPOWER, [
|
||||
0xFF, // request tx power
|
||||
]);
|
||||
|
||||
// read response from device
|
||||
const [ command, txPower ] = await this.readFromSerialPort();
|
||||
|
||||
const [ txPower ] = response;
|
||||
return txPower;
|
||||
|
||||
}
|
||||
|
||||
async getSpreadingFactor() {
|
||||
|
||||
await this.sendKissCommand([
|
||||
this.CMD_SF,
|
||||
const response = await this.sendCommand(this.CMD_SF, [
|
||||
0xFF, // request spreading factor
|
||||
]);
|
||||
|
||||
// read response from device
|
||||
const [ command, spreadingFactor ] = await this.readFromSerialPort();
|
||||
|
||||
const [ spreadingFactor ] = response;
|
||||
return spreadingFactor;
|
||||
|
||||
}
|
||||
|
||||
async getCodingRate() {
|
||||
|
||||
await this.sendKissCommand([
|
||||
this.CMD_CR,
|
||||
const response = await this.sendCommand(this.CMD_CR, [
|
||||
0xFF, // request coding rate
|
||||
]);
|
||||
|
||||
// read response from device
|
||||
const [ command, codingRate ] = await this.readFromSerialPort();
|
||||
|
||||
const [ codingRate ] = response;
|
||||
return codingRate;
|
||||
|
||||
}
|
||||
|
||||
async getRadioState() {
|
||||
|
||||
await this.sendKissCommand([
|
||||
this.CMD_RADIO_STATE,
|
||||
const response = await this.sendCommand(this.CMD_RADIO_STATE, [
|
||||
0xFF, // request radio state
|
||||
]);
|
||||
|
||||
// read response from device
|
||||
const [ command, radioState ] = await this.readFromSerialPort();
|
||||
|
||||
const [ radioState ] = response;
|
||||
return radioState;
|
||||
|
||||
}
|
||||
|
||||
async getRxStat() {
|
||||
|
||||
await this.sendKissCommand([
|
||||
this.CMD_STAT_RX,
|
||||
const response = await this.sendCommand(this.CMD_STAT_RX, [
|
||||
0x00,
|
||||
]);
|
||||
|
||||
// read response from device
|
||||
const [ command, ...statBytes ] = await this.readFromSerialPort();
|
||||
const [ ...statBytes ] = response;
|
||||
|
||||
// convert 4 bytes to 32bit integer
|
||||
const stat = statBytes[0] << 24 | statBytes[1] << 16 | statBytes[2] << 8 | statBytes[3];
|
||||
|
|
@ -494,13 +545,12 @@ class RNode {
|
|||
|
||||
async getTxStat() {
|
||||
|
||||
await this.sendKissCommand([
|
||||
this.CMD_STAT_TX,
|
||||
const response = await this.sendCommand(this.CMD_STAT_TX, [
|
||||
0x00,
|
||||
]);
|
||||
|
||||
// read response from device
|
||||
const [ command, ...statBytes ] = await this.readFromSerialPort();
|
||||
const [ ...statBytes ] = response;
|
||||
|
||||
// convert 4 bytes to 32bit integer
|
||||
const stat = statBytes[0] << 24 | statBytes[1] << 16 | statBytes[2] << 8 | statBytes[3];
|
||||
|
|
@ -510,14 +560,12 @@ class RNode {
|
|||
|
||||
async getRssiStat() {
|
||||
|
||||
await this.sendKissCommand([
|
||||
this.CMD_STAT_RSSI,
|
||||
const response = await this.sendCommand(this.CMD_STAT_RSSI, [
|
||||
0x00,
|
||||
]);
|
||||
|
||||
// read response from device
|
||||
const [ command, rssi ] = await this.readFromSerialPort();
|
||||
|
||||
const [ rssi ] = response;
|
||||
return rssi;
|
||||
|
||||
}
|
||||
|
|
@ -536,7 +584,23 @@ class RNode {
|
|||
]);
|
||||
}
|
||||
|
||||
async startBluetoothPairing() {
|
||||
async startBluetoothPairing(pinCallback) {
|
||||
|
||||
// listen for bluetooth pin
|
||||
// pin will be available once the user has initiated pairing from an Android device
|
||||
this.callbacks[this.CMD_BT_PIN] = (response) => {
|
||||
|
||||
// read response from device
|
||||
const [ ...pinBytes ] = response;
|
||||
|
||||
// convert 4 bytes to 32bit integer
|
||||
const pin = pinBytes[0] << 24 | pinBytes[1] << 16 | pinBytes[2] << 8 | pinBytes[3];
|
||||
|
||||
// tell user what the bluetooth pin is
|
||||
console.log("Bluetooth Pairing Pin: " + pin);
|
||||
pinCallback(pin);
|
||||
|
||||
};
|
||||
|
||||
// enable pairing
|
||||
await this.sendKissCommand([
|
||||
|
|
@ -544,43 +608,16 @@ class RNode {
|
|||
0x02, // enable pairing
|
||||
]);
|
||||
|
||||
// todo: listen for packets, pin will be available once user has initiated pairing from Android device
|
||||
|
||||
// // attempt to get bluetooth pairing pin
|
||||
// try {
|
||||
//
|
||||
// // read response from device
|
||||
// const [ command, ...pinBytes ] = await this.readFromSerialPort(5000);
|
||||
// if(command !== this.CMD_BT_PIN){
|
||||
// throw `unexpected command response: ${command}`;
|
||||
// }
|
||||
//
|
||||
// // convert 4 bytes to 32bit integer
|
||||
// const pin = pinBytes[0] << 24 | pinBytes[1] << 16 | pinBytes[2] << 8 | pinBytes[3];
|
||||
//
|
||||
// // todo: remove logs
|
||||
// console.log(pinBytes);
|
||||
// console.log(pin);
|
||||
//
|
||||
// // todo: convert to string
|
||||
// return pin;
|
||||
//
|
||||
// } catch(error) {
|
||||
// throw `failed to get bluetooth pin: ${error}`;
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
async readDisplay() {
|
||||
|
||||
await this.sendKissCommand([
|
||||
this.CMD_DISP_READ,
|
||||
const response = await this.sendCommand(this.CMD_DISP_READ, [
|
||||
0x01,
|
||||
]);
|
||||
|
||||
// read response from device
|
||||
const [ command, ...displayBuffer ] = await this.readFromSerialPort();
|
||||
|
||||
const [ ...displayBuffer ] = response;
|
||||
return displayBuffer;
|
||||
|
||||
}
|
||||
|
|
@ -715,6 +752,20 @@ class RNode {
|
|||
return new ROM(rom);
|
||||
}
|
||||
|
||||
async setDisplayRotation(rotation) {
|
||||
await this.sendKissCommand([
|
||||
this.CMD_DISP_ROT,
|
||||
rotation & 0xFF,
|
||||
]);
|
||||
}
|
||||
|
||||
async startDisplayReconditioning() {
|
||||
await this.sendKissCommand([
|
||||
this.CMD_DISP_RCND,
|
||||
0x01,
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ROM {
|
||||
|
|
@ -743,6 +794,7 @@ class ROM {
|
|||
static MODEL_A7 = 0xA7
|
||||
static MODEL_A5 = 0xA5;
|
||||
static MODEL_AA = 0xAA;
|
||||
static MODEL_AC = 0xAC;
|
||||
|
||||
static PRODUCT_T32_10 = 0xB2
|
||||
static MODEL_BA = 0xBA
|
||||
|
|
@ -766,6 +818,10 @@ class ROM {
|
|||
static MODEL_C5 = 0xC5
|
||||
static MODEL_CA = 0xCA
|
||||
|
||||
static PRODUCT_HELTEC_T114 = 0xC2
|
||||
static MODEL_C6 = 0xC6
|
||||
static MODEL_C7 = 0xC7
|
||||
|
||||
static PRODUCT_TBEAM = 0xE0
|
||||
static MODEL_E4 = 0xE4
|
||||
static MODEL_E9 = 0xE9
|
||||
|
|
@ -781,8 +837,8 @@ class ROM {
|
|||
static MODEL_D9 = 0xD9;
|
||||
|
||||
static PRODUCT_TECHO = 0x15;
|
||||
static MODEL_T4 = 0x16;
|
||||
static MODEL_T9 = 0x17;
|
||||
static MODEL_16 = 0x16;
|
||||
static MODEL_17 = 0x17;
|
||||
|
||||
static PRODUCT_HMBRW = 0xF0
|
||||
static MODEL_FF = 0xFF
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue