Structure client files
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
|
@ -1,7 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<svg viewBox="-1 -1 15 15" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<circle cx= "6" cy="10" r="2" style="stroke: #000;"/>
|
|
||||||
<circle cx="10" cy= "6" r="2" style="stroke: #000; fill: none;"/>
|
|
||||||
<circle cx= "2" cy= "6" r="2" style="stroke: #000; fill: none;"/>
|
|
||||||
<circle cx= "6" cy= "2" r="2" style="stroke: #000; fill: none;"/>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 369 B |
|
@ -1,7 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<svg viewBox="-1 -1 15 15" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<circle cx= "6" cy="10" r="2" style="stroke: #000; fill: none;"/>
|
|
||||||
<circle cx="10" cy= "6" r="2" style="stroke: #000;"/>
|
|
||||||
<circle cx= "2" cy= "6" r="2" style="stroke: #000; fill: none;"/>
|
|
||||||
<circle cx= "6" cy= "2" r="2" style="stroke: #000; fill: none;"/>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 369 B |
|
@ -1,7 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<svg viewBox="-1 -1 15 15" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<circle cx= "6" cy="10" r="2" style="stroke: #000; fill: none;"/>
|
|
||||||
<circle cx="10" cy= "6" r="2" style="stroke: #000; fill: none;"/>
|
|
||||||
<circle cx= "2" cy= "6" r="2" style="stroke: #000;"/>
|
|
||||||
<circle cx= "6" cy= "2" r="2" style="stroke: #000; fill: none;"/>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 369 B |
|
@ -1,7 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<svg viewBox="-1 -1 15 15" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<circle cx= "6" cy="10" r="2" style="stroke: #000; fill: none;"/>
|
|
||||||
<circle cx="10" cy= "6" r="2" style="stroke: #000; fill: none;"/>
|
|
||||||
<circle cx= "2" cy= "6" r="2" style="stroke: #000; fill: none;"/>
|
|
||||||
<circle cx= "6" cy= "2" r="2" style="stroke: #000;"/>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 369 B |
|
@ -1,11 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Chart-O-Matic</title>
|
|
||||||
<script type="module" src="chart.mjs"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>The Amazing Chart-O-Matic</h1>
|
|
||||||
<canvas id="chart" style="border: solid black 1px; width: 100%;"></canvas>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -11,17 +11,17 @@
|
||||||
|
|
||||||
<!-- Vail stuff -->
|
<!-- Vail stuff -->
|
||||||
<link rel="manifest" href="manifest.json">
|
<link rel="manifest" href="manifest.json">
|
||||||
<link rel="icon" href="vail.png" sizes="256x256" type="image/png">
|
<link rel="icon" href="assets/vail.png" sizes="256x256" type="image/png">
|
||||||
<link rel="icon" href="vail.svg" sizes="any" type="image/svg+xml">
|
<link rel="icon" href="assets/vail.svg" sizes="any" type="image/svg+xml">
|
||||||
<script type="module" src="vail.mjs"></script>
|
<script type="module" src="scripts/vail.mjs"></script>
|
||||||
<script type="module" src="ui.mjs"></script>
|
<script type="module" src="scripts/ui.mjs"></script>
|
||||||
<link rel="stylesheet" href="vail.css">
|
<link rel="stylesheet" href="vail.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar is-dark">
|
<nav class="navbar is-dark">
|
||||||
<div class="navbar-brand">
|
<div class="navbar-brand">
|
||||||
<a class="navbar-item">
|
<a class="navbar-item">
|
||||||
<img class="" src="vail.svg" alt="">
|
<img class="" src="assets/vail.svg" alt="">
|
||||||
<div class="block">Vail</div>
|
<div class="block">Vail</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
"theme_color": "#009688",
|
"theme_color": "#009688",
|
||||||
"description": "Internet Morse Code client",
|
"description": "Internet Morse Code client",
|
||||||
"icons": [
|
"icons": [
|
||||||
{"src": "vail.png", "sizes": "250x250"},
|
{"src": "assets/vail.png", "sizes": "250x250"},
|
||||||
{"src": "vail.svg", "sizes": "150x150"}
|
{"src": "assets/vail.svg", "sizes": "150x150"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -259,8 +259,8 @@ class TelegraphBuzzer extends AudioBuzzer{
|
||||||
|
|
||||||
this.hum = new Oscillator(140, 0.005, "sawtooth")
|
this.hum = new Oscillator(140, 0.005, "sawtooth")
|
||||||
|
|
||||||
this.closeSample = new Sample("telegraph-a.mp3")
|
this.closeSample = new Sample("../assets/telegraph-a.mp3")
|
||||||
this.openSample = new Sample("telegraph-b.mp3")
|
this.openSample = new Sample("../assets/telegraph-b.mp3")
|
||||||
}
|
}
|
||||||
|
|
||||||
async Buzz(tx, when=0) {
|
async Buzz(tx, when=0) {
|
|
@ -53,12 +53,13 @@ export class Vail {
|
||||||
"open",
|
"open",
|
||||||
msg => {
|
msg => {
|
||||||
this.connected = true
|
this.connected = true
|
||||||
this.rx(0, 0, {connected: true})
|
this.rx(0, 0, {connected: true, notice: "Repeater connected"})
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
this.socket.addEventListener(
|
this.socket.addEventListener(
|
||||||
"close",
|
"close",
|
||||||
msg => {
|
msg => {
|
||||||
|
this.rx(0, 0, {connected: false, notice: `Repeater disconnected: ${msg.reason}`})
|
||||||
console.error("Repeater connection dropped:", msg.reason)
|
console.error("Repeater connection dropped:", msg.reason)
|
||||||
setTimeout(() => this.reopen(), 2*Second)
|
setTimeout(() => this.reopen(), 2*Second)
|
||||||
}
|
}
|
||||||
|
@ -158,20 +159,20 @@ export class Vail {
|
||||||
export class Null {
|
export class Null {
|
||||||
constructor(rx, interval=3*Second) {
|
constructor(rx, interval=3*Second) {
|
||||||
this.rx = rx
|
this.rx = rx
|
||||||
this.interval = setInterval(() => this.pulse(), interval)
|
this.init()
|
||||||
this.pulse()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pulse() {
|
notice(msg) {
|
||||||
this.rx(0, 0, {note: "local", connected: false})
|
this.rx(0, 0, {connected: false, notice: msg})
|
||||||
}
|
}
|
||||||
|
|
||||||
Transmit(time, duration, squelch=true) {
|
init() {
|
||||||
|
this.notice("Null repeater: nobody will hear you.")
|
||||||
}
|
}
|
||||||
|
|
||||||
Close() {
|
Transmit(time, duration, squelch=true) {}
|
||||||
clearInterval(this.interval)
|
|
||||||
}
|
Close() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Echo extends Null {
|
export class Echo extends Null {
|
||||||
|
@ -180,6 +181,10 @@ export class Echo extends Null {
|
||||||
this.delay = delay
|
this.delay = delay
|
||||||
}
|
}
|
||||||
|
|
||||||
|
init () {
|
||||||
|
this.notice("Echo repeater: you can only hear yourself.")
|
||||||
|
}
|
||||||
|
|
||||||
Transmit(time, duration, squelch=true) {
|
Transmit(time, duration, squelch=true) {
|
||||||
this.rx(time + this.delay, duration, {note: "local"})
|
this.rx(time + this.delay, duration, {note: "local"})
|
||||||
}
|
}
|
||||||
|
@ -189,16 +194,19 @@ export class Fortune extends Null {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param rx Receive callback
|
* @param rx Receive callback
|
||||||
* @param {Keyer} keyer Keyer object
|
* @param {Keyer} keyer Robokeyer
|
||||||
*/
|
*/
|
||||||
constructor(rx, keyer) {
|
constructor(rx, keyer) {
|
||||||
super(rx, 1*Minute)
|
super(rx)
|
||||||
this.keyer = keyer
|
this.keyer = keyer
|
||||||
this.pulse()
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this.notice("Say something, and I will tell you your fortune.")
|
||||||
}
|
}
|
||||||
|
|
||||||
pulse() {
|
pulse() {
|
||||||
super.pulse()
|
this.timeout = null
|
||||||
if (!this.keyer || this.keyer.Busy()) {
|
if (!this.keyer || this.keyer.Busy()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -207,6 +215,13 @@ export class Fortune extends Null {
|
||||||
this.keyer.EnqueueAsciiString(`${fortune} \x04 `)
|
this.keyer.EnqueueAsciiString(`${fortune} \x04 `)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Transmit(time, duration, squelch=true) {
|
||||||
|
if (this.timeout) {
|
||||||
|
clearTimeout(this.timeout)
|
||||||
|
}
|
||||||
|
this.timeout = setTimeout(() => this.pulse(), 3 * Second)
|
||||||
|
}
|
||||||
|
|
||||||
Close() {
|
Close() {
|
||||||
this.keyer.Flush()
|
this.keyer.Flush()
|
||||||
super.Close()
|
super.Close()
|
|
@ -281,7 +281,7 @@ class VailClient {
|
||||||
number = Number(numberMatch[0])
|
number = Number(numberMatch[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name.startsWith("Fortunesf")) {
|
if (name.startsWith("Fortunes")) {
|
||||||
this.roboKeyer.SetPauseMultiplier(number || 1)
|
this.roboKeyer.SetPauseMultiplier(number || 1)
|
||||||
this.repeater = new Repeaters.Fortune(rx, this.roboKeyer)
|
this.repeater = new Repeaters.Fortune(rx, this.roboKeyer)
|
||||||
} else if (name.startsWith("Echo")) {
|
} else if (name.startsWith("Echo")) {
|
||||||
|
@ -291,8 +291,6 @@ class VailClient {
|
||||||
} else {
|
} else {
|
||||||
this.repeater = new Repeaters.Vail(rx, name)
|
this.repeater = new Repeaters.Vail(rx, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
toast(`Now using repeater: ${name}`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -371,6 +369,10 @@ class VailClient {
|
||||||
this.rxDurations.splice(20, 2)
|
this.rxDurations.splice(20, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stats.notice) {
|
||||||
|
toast(stats.notice)
|
||||||
|
}
|
||||||
|
|
||||||
let averageLag = (stats.averageLag || 0).toFixed(2)
|
let averageLag = (stats.averageLag || 0).toFixed(2)
|
||||||
let longestRxDuration = this.rxDurations.reduce((a,b) => Math.max(a,b))
|
let longestRxDuration = this.rxDurations.reduce((a,b) => Math.max(a,b))
|
||||||
let suggestedDelay = ((averageLag + longestRxDuration) * 1.2).toFixed(0)
|
let suggestedDelay = ((averageLag + longestRxDuration) * 1.2).toFixed(0)
|