diff --git a/index.html b/index.html
index d5a6e88..f363153 100644
--- a/index.html
+++ b/index.html
@@ -138,6 +138,7 @@
Message
CLI
GetStats
+ Ping
Set Path
Share (Zero Hop)
Export
@@ -501,6 +502,14 @@
}
},
+ async pingRepeater(contact) {
+ try {
+ const response = await this.connection.pingRepeaterZeroHop(contact.publicKey);
+ console.log(response);
+ } catch(e) {
+ console.log(e);
+ }
+ },
async reboot() {
try {
await this.connection.reboot();
diff --git a/src/connection/connection.js b/src/connection/connection.js
index dbbc75e..5eb2a89 100644
--- a/src/connection/connection.js
+++ b/src/connection/connection.js
@@ -3,6 +3,7 @@ import BufferReader from "../buffer_reader.js";
import Constants from "../constants.js";
import EventEmitter from "../events.js";
import BufferUtils from "../buffer_utils.js";
+import Packet from "../packet.js";
class Connection extends EventEmitter {
@@ -1421,6 +1422,88 @@ class Connection extends EventEmitter {
});
}
+ pingRepeaterZeroHop(contactPublicKey, timeoutMillis) {
+ return new Promise(async (resolve, reject) => {
+ try {
+
+ // create raw data using custom packet
+ const bufferWriter = new BufferWriter();
+ bufferWriter.writeUInt32LE(Date.now()); // timestamp millis so every ping is unique
+ bufferWriter.writeBytes([0x70, 0x69, 0x6E, 0x67]); // "ping" as bytes
+ bufferWriter.writeBytes(contactPublicKey.subarray(0, 2)); // 2 bytes from the repeaters public key, so we don't use another repeaters ping response
+ const rawBytes = bufferWriter.toBytes();
+
+ var startMillis = Date.now();
+
+ // resolve promise when we receive expected response
+ const onLogRxDataPush = (response) => {
+
+ // calculate round trip time
+ const endMillis = Date.now();
+ const durationMillis = endMillis - startMillis;
+
+ // parse packet from rx data, and make sure it's expected type
+ const packet = Packet.fromBytes(response.raw);
+ if(packet.payload_type !== Packet.PAYLOAD_TYPE_RAW_CUSTOM){
+ return;
+ }
+
+ // make sure the payload we sent, is the payload we received
+ if(!BufferUtils.areBuffersEqual(packet.payload, rawBytes)){
+ return;
+ }
+
+ // ping successful remove all listeners
+ this.off(Constants.ResponseCodes.Err, onErr);
+ this.off(Constants.PushCodes.LogRxData, onLogRxDataPush);
+
+ // send back results
+ resolve({
+ rtt: durationMillis,
+ snr: response.lastSnr,
+ rssi: response.lastRssi,
+ });
+
+ }
+
+ // reject promise when we receive err
+ const onErr = () => {
+ this.off(Constants.ResponseCodes.Err, onErr);
+ this.off(Constants.PushCodes.LogRxData, onLogRxDataPush);
+ reject();
+ }
+
+ // listen for events
+ this.once(Constants.ResponseCodes.Err, onErr);
+ this.on(Constants.PushCodes.LogRxData, onLogRxDataPush);
+
+ // check if a timeout was provided
+ if(timeoutMillis != null){
+ setTimeout(() => {
+
+ // stop listening for events
+ this.off(Constants.ResponseCodes.Err, onErr);
+ this.off(Constants.PushCodes.LogRxData, onLogRxDataPush);
+
+ // reject since it timed out
+ reject("timeout");
+
+ }, timeoutMillis);
+ }
+
+ // send raw data to repeater, for it to repeat zero hop
+ await this.sendCommandSendRawData([
+ // we set the repeater we want to ping as the path
+ // it should repeat our packet, and we can listen for it
+ contactPublicKey.subarray(0, 1),
+ ], rawBytes);
+
+ } catch(e) {
+ reject(e);
+ }
+ });
+ }
+
}
export default Connection;