diff --git a/index.html b/index.html index 733ee74..25263bb 100644 --- a/index.html +++ b/index.html @@ -197,6 +197,36 @@ +
+ +
+ 6. Configure Bluetooth (optional) +
+ +
+ +
+ + + +
+ +
+ +
+
+ Bluetooth is not supported on all devices. +
+
+ +
+
@@ -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) {