-
-
-
+
+
+
+
+
+
+
Connected to: {{ selfInfo.name }}
+
+
+
+
+
+
+
+ AppStart
+
+
+ SendSelfAdvert(ZeroHop)
+
+
+ SendSelfAdvert(Flood)
+
+
+ SetAdvertName
+
+
+ SetAdvertLatLon
+
+
+ RemoveContact
+
+
+ AddUpdateContact
+
+
+ SyncNextMessage
+
+
+ GetContacts
+
+
+ GetDeviceTime
+
+
+ SetDeviceTime
+
+
+ SetRadioParams
+
+
+ SetTxPower
+
+
+ ResetPath
+
+
+ SendTxtMsg
+
+
+
+
+
+
+
+
+
+
{{ contact.advName }}
+
Type: {{ contactTypeToString(contact.type) }} • Last Advert: {{ contact.lastAdvert }}
+
+
+
+
@@ -90,7 +130,9 @@
Vue.createApp({
data() {
return {
- device: null,
+ connection: null,
+ selfInfo: null,
+ contacts: [],
};
},
mounted() {
@@ -99,22 +141,48 @@
methods: {
async askForSerialPort() {
this.connection = await SerialConnection.open();
- this.connection.on("tx", (data) => console.log("tx", data));
- this.connection.on("rx", (data) => console.log("rx", data));
+ this.connection.on("connected", () => this.onConnected());
+ // this.connection.on("tx", (data) => console.log("tx", data));
+ // this.connection.on("rx", (data) => console.log("rx", data));
},
async askForBleDevice() {
this.connection = await BleConnection.open();
- this.connection.on("tx", (data) => console.log("tx", data));
- this.connection.on("rx", (data) => console.log("rx", data));
+ this.connection.on("connected", () => this.onConnected());
+ // this.connection.on("tx", (data) => console.log("tx", data));
+ // this.connection.on("rx", (data) => console.log("rx", data));
},
async disconnect() {
if(this.connection){
await this.connection.close();
- this.device = null;
+ this.connection = null;
+ }
+ },
+ async onConnected() {
+ console.log("connected");
+ await this.loadSelfInfo();
+ await this.loadContacts();
+ this.connection.on(Constants.PushCodes.Advert, async () => {
+ console.log("on advert");
+ await this.loadContacts();
+ });
+ },
+ async loadSelfInfo() {
+ this.selfInfo = await this.connection.getSelfInfo();
+ },
+ async loadContacts() {
+ this.contacts = await this.connection.getContacts();
+ },
+ contactTypeToString(type) {
+ switch(type){
+ case 0: return "Unknown";
+ case 1: return "Chat";
+ case 2: return "Repeater";
+ case 3: return "Room";
}
},
async sendCommandAppStart() {
- await this.connection.sendCommandAppStart();
+ const selfInfo = await this.connection.getSelfInfo();
+ console.log(selfInfo);
},
async sendCommandSendTxtMsg() {
const txtType = Constants.TxtTypes.Plain;
@@ -128,7 +196,8 @@
await this.connection.sendCommandSendSelfAdvert(type);
},
async sendCommandGetContacts() {
- await this.connection.sendCommandGetContacts();
+ this.contacts = await this.connection.getContacts();
+ console.log(this.contacts);
},
async sendCommandGetDeviceTime() {
await this.connection.sendCommandGetDeviceTime();
@@ -165,8 +234,9 @@
},
async sendCommandSetAdvertLatLon() {
- const lat = 123;
- const lon = 456;
+ const lat = Math.floor(-38.661727955271765 * 1000000);
+ const lon = Math.floor(178.0236810462527 * 1000000);
+ console.log(lat, lon);
await this.connection.sendCommandSetAdvertLatLon(lat, lon);
},
async sendCommandRemoveContact() {
@@ -188,6 +258,20 @@
async sendCommandSyncNextMessage() {
await this.connection.sendCommandSyncNextMessage();
},
+ async removeContact(contact) {
+
+ // ask user to confirm action
+ if(!confirm("Are you sure you want to remove this contact?")){
+ return;
+ }
+
+ // remove contact from device
+ await this.connection.sendCommandRemoveContact(contact.publicKey);
+
+ // reload contacts
+ await this.loadContacts();
+
+ },
},
}).mount('#app');
diff --git a/src/connection/ble_connection.js b/src/connection/ble_connection.js
index c8beff1..5abba2c 100644
--- a/src/connection/ble_connection.js
+++ b/src/connection/ble_connection.js
@@ -66,6 +66,9 @@ class BleConnection extends Connection {
this.onFrameReceived(frame);
});
+ // fire connected event
+ this.onConnected();
+
}
async close() {
diff --git a/src/connection/connection.js b/src/connection/connection.js
index 2bb0b5f..3c98d64 100644
--- a/src/connection/connection.js
+++ b/src/connection/connection.js
@@ -5,6 +5,10 @@ import EventEmitter from "../events.js";
class Connection extends EventEmitter {
+ onConnected() {
+ this.emit("connected");
+ }
+
async close() {
throw new Error("This method must be implemented by the subclass.");
}
@@ -166,32 +170,32 @@ class Connection extends EventEmitter {
}
onAdvertPush(bufferReader) {
- this.emit("AdvertPush", {
+ this.emit(Constants.PushCodes.Advert, {
publicKey: bufferReader.readBytes(32),
});
}
onSendConfirmedPush(bufferReader) {
- this.emit("SendConfirmedPush", {
+ this.emit(Constants.PushCodes.SendConfirmed, {
ackCode: bufferReader.readBytes(4),
roundTrip: bufferReader.readUInt32LE(),
});
}
onMsgWaitingPush(bufferReader) {
- this.emit("MsgWaitingPush", {
+ this.emit(Constants.PushCodes.MsgWaiting, {
});
}
onContactsStartResponse(bufferReader) {
- this.emit("ContactsStartResponse", {
+ this.emit(Constants.ResponseCodes.ContactsStart, {
count: bufferReader.readUInt32LE(),
});
}
onContactResponse(bufferReader) {
- this.emit("ContactResponse", {
+ this.emit(Constants.ResponseCodes.Contact, {
publicKey: bufferReader.readBytes(32),
type: bufferReader.readByte(),
flags: bufferReader.readByte(),
@@ -206,19 +210,19 @@ class Connection extends EventEmitter {
}
onEndOfContactsResponse(bufferReader) {
- this.emit("EndOfContactsResponse", {
+ this.emit(Constants.ResponseCodes.EndOfContacts, {
mostRecentLastmod: bufferReader.readUInt32LE(),
});
}
onSentResponse(bufferReader) {
- this.emit("SentResponse", {
+ this.emit(Constants.ResponseCodes.Sent, {
});
}
onSelfInfoResponse(bufferReader) {
- this.emit("SelfInfoResponse", {
+ this.emit(Constants.ResponseCodes.SelfInfo, {
type: bufferReader.readByte(),
txPower: bufferReader.readByte(),
maxTxPower: bufferReader.readByte(),
@@ -235,19 +239,19 @@ class Connection extends EventEmitter {
}
onCurrTimeResponse(bufferReader) {
- this.emit("CurrTimeResponse", {
+ this.emit(Constants.ResponseCodes.CurrTime, {
epochSecs: bufferReader.readUInt32LE(),
});
}
onNoMoreMessagesResponse(bufferReader) {
- this.emit("NoMoreMessagesResponse", {
+ this.emit(Constants.ResponseCodes.NoMoreMessages, {
});
}
onContactMsgRecvResponse(bufferReader) {
- this.emit("ContactMsgRecvResponse", {
+ this.emit(Constants.ResponseCodes.ContactMsgRecv, {
pubKeyPrefix: bufferReader.readBytes(6),
pathLen: bufferReader.readByte(),
txtType: bufferReader.readByte(),
@@ -256,6 +260,44 @@ class Connection extends EventEmitter {
});
}
+ getSelfInfo() {
+ return new Promise(async (resolve, reject) => {
+
+ // listen for response
+ this.once(Constants.ResponseCodes.SelfInfo, (selfInfo) => {
+ resolve(selfInfo);
+ });
+
+ // request self info
+ await this.sendCommandAppStart();
+
+ });
+ }
+
+ getContacts() {
+ return new Promise(async (resolve, reject) => {
+
+ // add contacts we receive to a list
+ const contacts = [];
+ const onContactReceived = (contact) => {
+ contacts.push(contact);
+ }
+
+ // listen for contacts
+ this.on(Constants.ResponseCodes.Contact, onContactReceived);
+
+ // there's no more contacts to receive, stop listening and resolve the promise
+ this.once(Constants.ResponseCodes.EndOfContacts, () => {
+ this.off(Constants.ResponseCodes.Contact, onContactReceived);
+ resolve(contacts);
+ });
+
+ // request contacts from device
+ await this.sendCommandGetContacts();
+
+ });
+ }
+
}
export default Connection;
diff --git a/src/connection/serial_connection.js b/src/connection/serial_connection.js
index 4b40276..3e90d92 100644
--- a/src/connection/serial_connection.js
+++ b/src/connection/serial_connection.js
@@ -6,12 +6,20 @@ import Connection from "./connection.js";
class SerialConnection extends Connection {
constructor(serialPort) {
+
super();
+
this.serialPort = serialPort;
this.reader = serialPort.readable.getReader();
this.writable = serialPort.writable;
this.readBuffer = [];
this.readLoop();
+
+ // fire connected callback after constructor has returned
+ setTimeout(() => {
+ this.onConnected();
+ }, 0);
+
}
static async open() {
diff --git a/src/events.js b/src/events.js
index 1a8f238..606fff2 100644
--- a/src/events.js
+++ b/src/events.js
@@ -26,6 +26,24 @@ class EventEmitter {
}
+ once(event, callback) {
+
+ // internal callback to handle the event
+ const internalCallback = (...data) => {
+
+ // we received an event, so lets remove the event listener
+ this.off(event, internalCallback);
+
+ // fire the original callback provided by the user
+ setTimeout(() => callback(...data), 0);
+
+ };
+
+ // listen to this event
+ this.on(event, internalCallback);
+
+ }
+
emit(event, ...data) {
// invoke each listener for this event