+
@@ -198,6 +201,7 @@
import Constants from "./src/constants.js";
import WebSerialConnection from "./src/connection/web_serial_connection.js";
import WebBleConnection from "./src/connection/web_ble_connection.js";
+ import WebSocketConnection from "./src/connection/websocket_connection.js";
import BufferUtils from "./src/buffer_utils.js";
Vue.createApp({
data() {
@@ -228,6 +232,11 @@
// this.connection.on("tx", (data) => console.log("tx", data));
// this.connection.on("rx", (data) => console.log("rx", data));
},
+ async askForWebSocketDevice() {
+ this.connection = await WebSocketConnection.open();
+ this.connection.on("connected", () => this.onConnected());
+ this.connection.on("disconnected", () => this.onDisconnected());
+ },
async disconnect() {
if(this.connection){
await this.connection.close();
@@ -390,7 +399,7 @@
console.log("syncNextMessage", message);
// check if contact message
- if(message.contactMessage){
+ if(message!= null && message.contactMessage){
// check if from cli contact
if(this.cliContact && BufferUtils.areBuffersEqual(message.contactMessage.pubKeyPrefix, this.cliContact.publicKey.subarray(0, 6))){
diff --git a/src/connection/connection.js b/src/connection/connection.js
index 90132cc..0d274fc 100644
--- a/src/connection/connection.js
+++ b/src/connection/connection.js
@@ -39,7 +39,7 @@ class Connection extends EventEmitter {
data.writeByte(Constants.CommandCodes.AppStart);
data.writeByte(1); // appVer
data.writeBytes(new Uint8Array(6)); // reserved
- data.writeString("test"); // appName
+ data.writeString("test client"); // appName
await this.sendToRadioFrame(data.toBytes());
}
@@ -334,6 +334,10 @@ class Connection extends EventEmitter {
this.onContactMsgRecvResponse(bufferReader);
} else if(responseCode === Constants.ResponseCodes.ChannelMsgRecv){
this.onChannelMsgRecvResponse(bufferReader);
+ } else if(responseCode === Constants.ResponseCodes.ContactMsgRecv3){
+ this.onContactMsgRecvResponse(bufferReader);
+ } else if(responseCode === Constants.ResponseCodes.ChannelMsgRecv3){
+ this.onChannelMsgRecvResponse(bufferReader);
} else if(responseCode === Constants.ResponseCodes.ContactsStart){
this.onContactsStartResponse(bufferReader);
} else if(responseCode === Constants.ResponseCodes.Contact){
@@ -635,23 +639,50 @@ class Connection extends EventEmitter {
}
onContactMsgRecvResponse(bufferReader) {
- this.emit(Constants.ResponseCodes.ContactMsgRecv, {
+
+ if (Constants.SupportedCompanionProtocolVersion >= 3) {
+ this.emit(Constants.ResponseCodes.ContactMsgRecv3, {
+ snr: bufferReader.readByte() / 4.0,
+ reserved1: bufferReader.readByte(),
+ reserved2: bufferReader.readByte(),
pubKeyPrefix: bufferReader.readBytes(6),
pathLen: bufferReader.readByte(),
txtType: bufferReader.readByte(),
senderTimestamp: bufferReader.readUInt32LE(),
text: bufferReader.readString(),
- });
- }
-
- onChannelMsgRecvResponse(bufferReader) {
- this.emit(Constants.ResponseCodes.ChannelMsgRecv, {
- channelIdx: bufferReader.readInt8(), // reserved (0 for now, ie. 'public')
- pathLen: bufferReader.readByte(), // 0xFF if was sent direct, otherwise hop count for flood-mode
+ });
+ } else {
+ this.emit(Constants.ResponseCodes.ContactMsgRecv, {
+ pubKeyPrefix: bufferReader.readBytes(6),
+ pathLen: bufferReader.readByte(),
txtType: bufferReader.readByte(),
senderTimestamp: bufferReader.readUInt32LE(),
text: bufferReader.readString(),
- });
+ });
+ }
+ }
+
+ onChannelMsgRecvResponse(bufferReader) {
+ if (Constants.SupportedCompanionProtocolVersion >= 3) {
+ this.emit(Constants.ResponseCodes.ChannelMsgRecv3, {
+ snr: bufferReader.readByte() / 4.0,
+ reserved1: bufferReader.readByte(),
+ reserved2: bufferReader.readByte(),
+ channelIdx: bufferReader.readInt8(), // reserved (0 for now, ie. 'public')
+ pathLen: bufferReader.readByte(), // 0xFF if was sent direct, otherwise hop count for flood-mode
+ txtType: bufferReader.readByte(),
+ senderTimestamp: bufferReader.readUInt32LE(),
+ text: bufferReader.readString(),
+ });
+ } else {
+ this.emit(Constants.ResponseCodes.ChannelMsgRecv, {
+ channelIdx: bufferReader.readInt8(), // reserved (0 for now, ie. 'public')
+ pathLen: bufferReader.readByte(), // 0xFF if was sent direct, otherwise hop count for flood-mode
+ txtType: bufferReader.readByte(),
+ senderTimestamp: bufferReader.readUInt32LE(),
+ text: bufferReader.readString(),
+ });
+ }
}
getSelfInfo(timeoutMillis = null) {
@@ -963,6 +994,8 @@ class Connection extends EventEmitter {
const onContactMessageReceived = (message) => {
this.off(Constants.ResponseCodes.ContactMsgRecv, onContactMessageReceived);
this.off(Constants.ResponseCodes.ChannelMsgRecv, onChannelMessageReceived);
+ this.off(Constants.ResponseCodes.ContactMsgRecv3, onContactMessageReceived);
+ this.off(Constants.ResponseCodes.ChannelMsgRecv3, onChannelMessageReceived);
this.off(Constants.ResponseCodes.NoMoreMessages, onNoMoreMessagesReceived);
resolve({
contactMessage: message,
@@ -973,6 +1006,8 @@ class Connection extends EventEmitter {
const onChannelMessageReceived = (message) => {
this.off(Constants.ResponseCodes.ContactMsgRecv, onContactMessageReceived);
this.off(Constants.ResponseCodes.ChannelMsgRecv, onChannelMessageReceived);
+ this.off(Constants.ResponseCodes.ContactMsgRecv3, onContactMessageReceived);
+ this.off(Constants.ResponseCodes.ChannelMsgRecv3, onChannelMessageReceived);
this.off(Constants.ResponseCodes.NoMoreMessages, onNoMoreMessagesReceived);
resolve({
channelMessage: message,
@@ -983,6 +1018,8 @@ class Connection extends EventEmitter {
const onNoMoreMessagesReceived = () => {
this.off(Constants.ResponseCodes.ContactMsgRecv, onContactMessageReceived);
this.off(Constants.ResponseCodes.ChannelMsgRecv, onChannelMessageReceived);
+ this.off(Constants.ResponseCodes.ContactMsgRecv3, onContactMessageReceived);
+ this.off(Constants.ResponseCodes.ChannelMsgRecv3, onChannelMessageReceived);
this.off(Constants.ResponseCodes.NoMoreMessages, onNoMoreMessagesReceived);
resolve(null);
}
@@ -990,6 +1027,8 @@ class Connection extends EventEmitter {
// listen for events
this.once(Constants.ResponseCodes.ContactMsgRecv, onContactMessageReceived);
this.once(Constants.ResponseCodes.ChannelMsgRecv, onChannelMessageReceived);
+ this.once(Constants.ResponseCodes.ContactMsgRecv3, onContactMessageReceived);
+ this.once(Constants.ResponseCodes.ChannelMsgRecv3, onChannelMessageReceived);
this.once(Constants.ResponseCodes.NoMoreMessages, onNoMoreMessagesReceived);
// sync next message from device
diff --git a/src/connection/websocket_connection.js b/src/connection/websocket_connection.js
new file mode 100644
index 0000000..88c79fe
--- /dev/null
+++ b/src/connection/websocket_connection.js
@@ -0,0 +1,73 @@
+import Connection from "./connection.js";
+
+// Easy way to test this is to run `websocat -s 5000`
+
+class WebSocketConnection extends Connection {
+
+ constructor(url) {
+ super();
+
+ let self = this
+ this.isClosing = false
+
+ let socket = new WebSocket(url)
+ socket.onopen = (event) => {
+ //console.log("connected")
+ this.onConnected();
+ }
+ socket.onerror = function(error) {
+ //console.log(error);
+ self.isClosing = true
+ self.onDisconnected();
+ }
+ socket.onmessage = async function(event) {
+ //console.log('got message', event.data)
+ let buf = await event.data.arrayBuffer();
+ self.onFrameReceived(buf);
+ }
+ socket.onclose = function() {
+ if (!self.isClosing) {
+ self.onDisconnected();
+ }
+ }
+ this.socket = socket
+ }
+
+ static async open() {
+
+ // ensure browser supports web bluetooth
+ let url = prompt("Enter WebSocket URL", "ws://127.0.0.1:5000")
+ if (url.startsWith("ws://") || url.startsWith("wss://")) {
+ } else {
+ url = "ws://" + url
+ }
+
+ return new WebSocketConnection(url);
+ }
+
+ async close() {
+ try {
+ this.isClosing = true
+ this.socket.close()
+ } catch(e) {
+ //console.log("close error", e)
+ // ignore error when disconnecting
+ }
+ }
+
+ async write(bytes) {
+ try {
+ this.socket.send(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 WebSocketConnection;
diff --git a/src/constants.js b/src/constants.js
index 2eb2706..229a4b3 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -1,6 +1,6 @@
class Constants {
- static SupportedCompanionProtocolVersion = 1;
+ static SupportedCompanionProtocolVersion = 3;
static SerialFrameTypes = {
Incoming: 0x3e, // ">"
@@ -71,6 +71,8 @@ class Constants {
DeviceInfo: 13,
PrivateKey: 14,
Disabled: 15,
+ ContactMsgRecv3: 16,
+ ChannelMsgRecv3: 17,
ChannelInfo: 18,
SignStart: 19,
Signature: 20,
diff --git a/src/index.js b/src/index.js
index af95004..ff42c31 100644
--- a/src/index.js
+++ b/src/index.js
@@ -4,6 +4,7 @@ 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 WebSocketConnection from "./connection/websocket_connection.js";
import Constants from "./constants.js";
import Advert from "./advert.js";
import Packet from "./packet.js";
@@ -17,6 +18,7 @@ export {
NodeJSSerialConnection,
WebSerialConnection,
TCPConnection,
+ WebSocketConnection,
Constants,
Advert,
Packet,