diff --git a/index.html b/index.html index ddd46d0..1d178c3 100644 --- a/index.html +++ b/index.html @@ -110,6 +110,9 @@ + @@ -526,6 +529,14 @@ alert("Failed to get battery voltage!"); } }, + async getChannels() { + try { + const response = await this.connection.getChannels(); + console.log(response); + } catch(e) { + alert("Failed to get channels!"); + } + }, async login(contact) { // ask user for password diff --git a/src/buffer_reader.js b/src/buffer_reader.js index a4f5e07..3dfe896 100644 --- a/src/buffer_reader.js +++ b/src/buffer_reader.js @@ -5,6 +5,10 @@ class BufferReader { this.buffer = new Uint8Array(data); } + getRemainingBytesCount() { + return this.buffer.length - this.pointer; + } + readByte() { return this.readBytes(1)[0]; } @@ -16,8 +20,7 @@ class BufferReader { } readRemainingBytes() { - const remainingBytesCount = this.buffer.length - this.pointer; - return this.readBytes(remainingBytesCount); + return this.readBytes(this.getRemainingBytesCount()); } readString() { @@ -47,6 +50,12 @@ class BufferReader { 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); diff --git a/src/connection/connection.js b/src/connection/connection.js index 5eb2a89..5b6bb67 100644 --- a/src/connection/connection.js +++ b/src/connection/connection.js @@ -231,6 +231,13 @@ class Connection extends EventEmitter { await this.sendToRadioFrame(data.toBytes()); } + async sendCommandGetChannel(channelIdx) { + const data = new BufferWriter(); + data.writeByte(Constants.CommandCodes.GetChannel); + data.writeByte(channelIdx); + await this.sendToRadioFrame(data.toBytes()); + } + onFrameReceived(frame) { // emit received frame @@ -271,6 +278,8 @@ class Connection extends EventEmitter { this.onPrivateKeyResponse(bufferReader); } else if(responseCode === Constants.ResponseCodes.Disabled){ this.onDisabledResponse(bufferReader); + } else if(responseCode === Constants.ResponseCodes.ChannelInfo){ + this.onChannelInfoResponse(bufferReader); } else if(responseCode === Constants.PushCodes.Advert){ this.onAdvertPush(bufferReader); } else if(responseCode === Constants.PushCodes.PathUpdated){ @@ -430,6 +439,23 @@ class Connection extends EventEmitter { }); } + onChannelInfoResponse(bufferReader) { + + const idx = bufferReader.readUInt8(); + const remainingBytesLength = bufferReader.getRemainingBytesCount(); + + // 128-bit keys + if(remainingBytesLength === 16){ + this.emit(Constants.ResponseCodes.ChannelInfo, { + channelIdx: idx, + secret: bufferReader.readBytes(remainingBytesLength), + }); + } else { + console.log(`ChannelInfo has unexpected key length: ${remainingBytesLength}`); + } + + } + onSelfInfoResponse(bufferReader) { this.emit(Constants.ResponseCodes.SelfInfo, { type: bufferReader.readByte(), @@ -1504,6 +1530,62 @@ class Connection extends EventEmitter { }); } + getChannel(channelIdx) { + return new Promise(async (resolve, reject) => { + try { + + // resolve promise when we receive channel info response + const onChannelInfoResponse = (response) => { + this.off(Constants.ResponseCodes.ChannelInfo, onChannelInfoResponse); + this.off(Constants.ResponseCodes.Err, onErr); + resolve(response); + } + + // reject promise when we receive err + const onErr = () => { + this.off(Constants.ResponseCodes.ChannelInfo, onChannelInfoResponse); + this.off(Constants.ResponseCodes.Err, onErr); + reject(); + } + + // listen for events + this.once(Constants.ResponseCodes.ChannelInfo, onChannelInfoResponse); + this.once(Constants.ResponseCodes.Err, onErr); + + // get channel + await this.sendCommandGetChannel(channelIdx); + + } catch(e) { + reject(e); + } + }); + } + + getChannels() { + return new Promise(async (resolve, reject) => { + + // add channels we receive to a list + var channelIdx = 0; + const channels = []; + while(true){ + + // try to get next channel + try { + const channel = await this.getChannel(channelIdx); + channels.push(channel); + } catch(e){ + break; + } + + channelIdx++; + + } + + return resolve(channels); + + }); + } + } export default Connection; diff --git a/src/constants.js b/src/constants.js index 5dbc360..2941cd9 100644 --- a/src/constants.js +++ b/src/constants.js @@ -39,6 +39,8 @@ class Constants { SendRawData: 25, SendLogin: 26, // todo SendStatusReq: 27, // todo + GetChannel: 31, + SetChannel: 32, } static ResponseCodes = { @@ -58,6 +60,7 @@ class Constants { DeviceInfo: 13, PrivateKey: 14, Disabled: 15, + ChannelInfo: 18, } static PushCodes = {