diff --git a/index.html b/index.html
index 733ee74..25263bb 100644
--- a/index.html
+++ b/index.html
@@ -197,6 +197,36 @@
+
@@ -1317,6 +1347,119 @@
await rnode.close();
alert("TNC mode has been disabled!");
+ },
+ 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!");
+ 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;
+ }
+
+ // enable bluetooth
+ console.log("enabling bluetooth");
+ await rnode.enableBluetooth();
+ console.log("enabling bluetooth: done");
+
+ await Utils.sleepMillis(1000);
+
+ // done
+ 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!");
+ 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;
+ }
+
+ // disable bluetooth
+ console.log("disabling bluetooth");
+ await rnode.disableBluetooth();
+ console.log("disabling bluetooth: done");
+
+ await Utils.sleepMillis(1000);
+
+ // done
+ 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!");
+ 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;
+ }
+
+ // start bluetooth pairing
+ try {
+ console.log("start bluetooth pairing");
+ const pin = await rnode.startBluetoothPairing();
+ console.log("start bluetooth pairing: done");
+ alert(`Bluetooth Pairing Pin: ${pin}`);
+ } catch(error) {
+ alert(error);
+ }
+
+ // done
+ await rnode.close();
+
},
async readAsBinaryString(blob) {
return new Promise((resolve, reject) => {
diff --git a/js/rnode.js b/js/rnode.js
index 4848c5b..3634b4b 100644
--- a/js/rnode.js
+++ b/js/rnode.js
@@ -147,32 +147,48 @@ class RNode {
}
}
- async readFromSerialPort() {
- const reader = this.readable.getReader();
- 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){
- return this.handleKISSFrame(buffer);
+ async readFromSerialPort(timeoutMillis) {
+ return new Promise(async (resolve, reject) => {
+
+ // create reader
+ const reader = this.readable.getReader();
+
+ // 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
}
- buffer = [this.KISS_FEND]; // Start new frame
}
}
}
+ } catch (error) {
+ console.error('Error reading from serial port: ', error);
+ } finally {
+ reader.releaseLock();
}
- } catch (error) {
- console.error('Error reading from serial port: ', error);
- } finally {
- reader.releaseLock();
- }
+
+ });
}
handleKISSFrame(frame) {
@@ -515,10 +531,36 @@ class RNode {
}
async startBluetoothPairing() {
+
+ // enable pairing
await this.sendKissCommand([
this.CMD_BT_CTRL,
0x02, // enable pairing
]);
+
+ // 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 setFrequency(frequencyInHz) {