diff --git a/cmd/vail/message.go b/cmd/vail/message.go
index ef036e4..eb98270 100644
--- a/cmd/vail/message.go
+++ b/cmd/vail/message.go
@@ -3,7 +3,6 @@ package main
import (
"bytes"
"encoding/binary"
- "fmt"
"time"
)
diff --git a/static/index.html b/static/index.html
index 970e203..43e6987 100644
--- a/static/index.html
+++ b/static/index.html
@@ -72,7 +72,7 @@
-
+
diff --git a/static/outputs.mjs b/static/outputs.mjs
index 6cfa56d..f4f251c 100644
--- a/static/outputs.mjs
+++ b/static/outputs.mjs
@@ -137,6 +137,10 @@ class Sample {
* A (mostly) virtual class defining a buzzer.
*/
class Buzzer {
+ constructor() {
+ this.connected = true
+ }
+
/**
* Signal an error
*/
@@ -175,6 +179,15 @@ class Buzzer {
this.Buzz(tx, when)
this.Silence(tx, when + duration)
}
+
+ /**
+ * Set the "connectedness" indicator.
+ *
+ * @param {boolean} connected True if connected
+ */
+ SetConnected(connected) {
+ this.connected = connected
+ }
}
class AudioBuzzer extends Buzzer {
@@ -297,6 +310,17 @@ class LampBuzzer extends Buzzer {
ms,
)
}
+
+ SetConnected(connected) {
+ console.log(connected)
+ for (let e of this.elements) {
+ if (connected) {
+ e.classList.add("connected")
+ } else {
+ e.classList.remove("connected")
+ }
+ }
+ }
}
class MIDIBuzzer extends Buzzer {
@@ -415,7 +439,7 @@ class Collection {
*
* @param tx True if transmitting
*/
- Silence(tx=False) {
+ Silence(tx=false) {
for (let b of this.collection) {
b.Silence(tx)
}
@@ -433,6 +457,19 @@ class Collection {
b.BuzzDuration(tx, when, duration)
}
}
+
+ /**
+ * Update the "connected" status display.
+ *
+ * For example, turn the receive light to black if the repeater is not connected.
+ *
+ * @param {boolean} connected True if we are "connected"
+ */
+ SetConnected(connected) {
+ for (let b of this.collection) {
+ b.SetConnected(connected)
+ }
+ }
}
export {AudioReady, Collection}
diff --git a/static/repeaters.mjs b/static/repeaters.mjs
index c943801..a2469ef 100644
--- a/static/repeaters.mjs
+++ b/static/repeaters.mjs
@@ -30,6 +30,7 @@ export class Vail {
this.lagDurations = []
this.sent = []
this.wantConnected = true
+ this.connected = false
this.wsUrl = new URL("chat", window.location)
this.wsUrl.protocol = this.wsUrl.protocol.replace("http", "ws")
@@ -43,10 +44,18 @@ export class Vail {
if (!this.wantConnected) {
return
}
+ this.rx(0, 0, {connected: false})
console.info("Attempting to reconnect", this.wsUrl.href)
this.clockOffset = 0
this.socket = new WebSocket(this.wsUrl, ["json.vail.woozle.org"])
this.socket.addEventListener("message", e => this.wsMessage(e))
+ this.socket.addEventListener(
+ "open",
+ msg => {
+ this.connected = true
+ this.rx(0, 0, {connected: true})
+ }
+ )
this.socket.addEventListener(
"close",
msg => {
@@ -71,6 +80,7 @@ export class Vail {
averageLag: this.lagDurations.reduce((a,b) => (a+b), 0) / this.lagDurations.length,
clockOffset: this.clockOffset,
clients: msg.Clients,
+ connected: this.connected,
}
console.log(msg)
if (typeof(msg) == "string") {
@@ -152,13 +162,14 @@ export class Vail {
}
export class Null {
- constructor(rx) {
+ constructor(rx, interval=3*Second) {
this.rx = rx
- this.interval = setInterval(() => this.pulse(), 3 * Second)
+ this.interval = setInterval(() => this.pulse(), interval)
+ this.pulse()
}
pulse() {
- this.rx(0, 0, {note: "local"})
+ this.rx(0, 0, {note: "local", connected: false})
}
Transmit(time, duration, squelch=true) {
@@ -169,51 +180,41 @@ export class Null {
}
}
-export class Echo {
+export class Echo extends Null {
constructor(rx, delay=0) {
- this.rx = rx
+ super(rx)
this.delay = delay
- this.Transmit(0, 0)
}
Transmit(time, duration, squelch=true) {
this.rx(time + this.delay, duration, {note: "local"})
}
-
- Close() {
- }
}
-export class Fortune {
+export class Fortune extends Null {
/**
*
* @param rx Receive callback
* @param {Keyer} keyer Keyer object
*/
constructor(rx, keyer) {
- this.rx = rx
+ super(rx, 1*Minute)
this.keyer = keyer
-
- this.interval = setInterval(() => this.pulse(), 1 * Minute)
this.pulse()
}
pulse() {
- this.rx(0, 0, {note: "local"})
- if (this.keyer.Busy()) {
+ super.pulse()
+ if (!this.keyer || this.keyer.Busy()) {
return
}
let fortune = GetFortune()
- this.keyer.EnqueueAsciiString(`${fortune}\x04 `)
- }
-
- Transmit(time, duration, squelch=true) {
- // Do nothing.
+ this.keyer.EnqueueAsciiString(`${fortune} \x04 `)
}
Close() {
this.keyer.Flush()
- clearInterval(this.interval)
+ super.Close()
}
}
\ No newline at end of file
diff --git a/static/vail.css b/static/vail.css
index f35723b..1d81081 100644
--- a/static/vail.css
+++ b/static/vail.css
@@ -16,7 +16,15 @@
-webkit-user-select: none; /* 2022-04-26 Safari still needs this */
}
-.recv-lamp.rx {
+.tag.recv-lamp {
+ background-color: #444;
+ color: white;
+}
+.tag.recv-lamp.connected {
+ background-color: #fec;
+}
+.tag.recv-lamp.rx,
+.tag.recv-lamp.connected.rx {
background-color: orange;
}
diff --git a/static/vail.mjs b/static/vail.mjs
index 508ed80..938b7da 100644
--- a/static/vail.mjs
+++ b/static/vail.mjs
@@ -375,6 +375,9 @@ class VailClient {
let longestRxDuration = this.rxDurations.reduce((a,b) => Math.max(a,b))
let suggestedDelay = ((averageLag + longestRxDuration) * 1.2).toFixed(0)
+ if (stats.connected !== undefined) {
+ this.outputs.SetConnected(stats.connected)
+ }
this.updateReading("#note", stats.note || "☁")
this.updateReading("#lag-value", averageLag)
this.updateReading("#longest-rx-value", longestRxDuration)