diff --git a/index.html b/index.html index 68b1506..a9b0eed 100644 --- a/index.html +++ b/index.html @@ -1,16 +1,25 @@ + MeshCore + + + + -
+
@@ -20,63 +29,94 @@
+
- -
- - - - - - - - - - - - - - - - - - +
+
+ +
+ + +
+
+
Connected to: {{ selfInfo.name }}
+
+
+ + +
+
+ + + + + + + + + + + + + + + +
+
+ + +
+
+
+
+
{{ contact.advName }}
+
Type: {{ contactTypeToString(contact.type) }} • Last Advert: {{ contact.lastAdvert }}
+
+
+
Forget
+
+
+
@@ -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