mirror of https://github.com/nealey/vail.git
Many client updates
This commit is contained in:
parent
56486979a8
commit
3a16ebb7af
|
@ -34,7 +34,8 @@
|
||||||
<div class="mdl-layout__drawer">
|
<div class="mdl-layout__drawer">
|
||||||
<span class="mdl-layout-title">Repeaters</span>
|
<span class="mdl-layout-title">Repeaters</span>
|
||||||
<nav class="mdl-navigation">
|
<nav class="mdl-navigation">
|
||||||
<a class="mdl-navigation__link" href="?repeater=">1-15 WPM</a>
|
<a class="mdl-navigation__link" href="?repeater=">General Chaos</a>
|
||||||
|
<a class="mdl-navigation__link" href="?repeater=beg">1-15 WPM</a>
|
||||||
<a class="mdl-navigation__link" href="?repeater=int">16-20 WPM</a>
|
<a class="mdl-navigation__link" href="?repeater=int">16-20 WPM</a>
|
||||||
<a class="mdl-navigation__link" href="?repeater=adv">21-99 WPM</a>
|
<a class="mdl-navigation__link" href="?repeater=adv">21-99 WPM</a>
|
||||||
</nav>
|
</nav>
|
||||||
|
@ -48,9 +49,7 @@
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="mdl-card mdl-shadow--4dp">
|
<div class="mdl-card mdl-shadow--4dp">
|
||||||
<div class="mdl-card__title">
|
<div class="mdl-card__title">
|
||||||
<h2 class="mdl-card__title-text">
|
<h2 class="mdl-card__title-text">Input</h2>
|
||||||
Input
|
|
||||||
</h2>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="mdl-tabs mdl-js-tabs mdl-js-ripple-effect">
|
<div class="mdl-tabs mdl-js-tabs mdl-js-ripple-effect">
|
||||||
<div class="mdl-tabs__tab-bar">
|
<div class="mdl-tabs__tab-bar">
|
||||||
|
@ -69,7 +68,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<code>⇧</code>
|
<kbd>c</kbd> or <kbd>,</kbd> or <kbd>⇧ Shift</kbd>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
@ -90,10 +89,12 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<code>.</code> or <code>z</code>
|
<kbd>.</kbd> or <kbd>z</kbd>
|
||||||
|
<br>
|
||||||
|
right-click for Dah
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<code>/</code> or <code>x</code>
|
<kbd>/</kbd> or <kbd>x</kbd>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
@ -117,13 +118,42 @@
|
||||||
|
|
||||||
<div class="mdl-card mdl-shadow--4dp">
|
<div class="mdl-card mdl-shadow--4dp">
|
||||||
<div class="mdl-card__title">
|
<div class="mdl-card__title">
|
||||||
<h2 class="mdl-card__title-text">
|
<h2 class="mdl-card__title-text">Knobs</h2>
|
||||||
Knobs
|
|
||||||
</h2>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="mdl-card__supporting-text">
|
<div class="mdl-card__supporting-text">
|
||||||
|
<p>
|
||||||
|
Dit length (iambic):
|
||||||
|
<output id="iambic-duration-value"></output>ms
|
||||||
|
<input
|
||||||
|
id="iambic-duration"
|
||||||
|
class="mdl-slider mdl-js-slider"
|
||||||
|
type="range"
|
||||||
|
min="40"
|
||||||
|
max="255"
|
||||||
|
value="100">
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Recieve delay:
|
||||||
|
<output id="rx-delay-value"></output>ms
|
||||||
|
<input
|
||||||
|
id="rx-delay"
|
||||||
|
class="mdl-slider mdl-js-slider"
|
||||||
|
type="range"
|
||||||
|
min="0"
|
||||||
|
max="9999"
|
||||||
|
value="4000">
|
||||||
|
</p>
|
||||||
|
<hr>
|
||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
Suggested receive delay:
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<output id="suggested-delay-value">0</output>ms
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
Average round-trip time:
|
Average round-trip time:
|
||||||
|
@ -142,47 +172,23 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
Suggested receive delay:
|
Repeater:
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<output id="suggested-delay-value">0</output>ms
|
<span id="repeater"></span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<hr>
|
<hr>
|
||||||
<p>
|
<p>Errors</p>
|
||||||
Recieve delay:
|
<div id="errors"></div>
|
||||||
<output id="rx-delay-value"></output>ms
|
|
||||||
<input
|
|
||||||
id="rx-delay"
|
|
||||||
class="mdl-slider mdl-js-slider"
|
|
||||||
type="range"
|
|
||||||
min="0"
|
|
||||||
max="5000"
|
|
||||||
value="400">
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Dit length (iambic):
|
|
||||||
<output id="iambic-duration-value"></output>ms
|
|
||||||
<input
|
|
||||||
id="iambic-duration"
|
|
||||||
class="mdl-slider mdl-js-slider"
|
|
||||||
type="range"
|
|
||||||
min="40"
|
|
||||||
max="255"
|
|
||||||
value="100">
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mdl-card mdl-shadow--4dp">
|
<div class="mdl-card mdl-shadow--4dp">
|
||||||
<div class="mdl-card__title">
|
<div class="mdl-card__title">
|
||||||
<h2 class="mdl-card__title-text">
|
<h2 class="mdl-card__title-text">Code Tree</h2>
|
||||||
Code Tree
|
|
||||||
</h2>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="mdl-card__supporting-text">
|
<div class="mdl-card__supporting-text">
|
||||||
<img src="code-tree.png">
|
<img src="code-tree.png">
|
||||||
|
@ -191,9 +197,7 @@
|
||||||
|
|
||||||
<div class="mdl-card mdl-shadow--4dp">
|
<div class="mdl-card mdl-shadow--4dp">
|
||||||
<div class="mdl-card__title">
|
<div class="mdl-card__title">
|
||||||
<h2 class="mdl-card__title-text">
|
<h2 class="mdl-card__title-text">Vail</h2>
|
||||||
Vail
|
|
||||||
</h2>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="mdl-card__supporting-text">
|
<div class="mdl-card__supporting-text">
|
||||||
<p>
|
<p>
|
||||||
|
@ -220,6 +224,99 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mdl-card mdl-shadow--4dp">
|
||||||
|
<div class="mdl-card__title">
|
||||||
|
<h2 class="mdl-card__title-text">How It Works</h2>
|
||||||
|
</div>
|
||||||
|
<div class="mdl-card__supporting-text">
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The Internet isn't exactly like radio waves:
|
||||||
|
it still goes at near the speed of light,
|
||||||
|
but there are multiple hops between endpoints,
|
||||||
|
which buffer up transmissions, and multiplex them onto a single uplink connection.
|
||||||
|
These repeaters (routers)
|
||||||
|
are also allowed to just drop things if they need to.
|
||||||
|
It's the responsibility of the communicating parties
|
||||||
|
to work out whether something needs to be retransmitted.
|
||||||
|
Because of this,
|
||||||
|
there's no telling how long it will take for a transmission to get to a destination.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Each Vail transmission (packet) consists of:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>timestamp (milliseconds since 1 Jan 1970, 00:00:00 in Reykjavík)</li>
|
||||||
|
<li>transmission duration (milliseconds)</li>
|
||||||
|
<li>silence duration (milliseconds, optional)</li>
|
||||||
|
<li>transmission duration (milliseconds, optional)</li>
|
||||||
|
<li>silence duration (milliseconds, optional)</li>
|
||||||
|
<li>Repeat as necessary</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The repeater does nothing but broadcast everything it gets
|
||||||
|
to every connected Vail client,
|
||||||
|
including the one that sent the packet.
|
||||||
|
When your client gets back the exact same thing it sent,
|
||||||
|
it compares the current time to the time in the packet.
|
||||||
|
This is the <i>round-trip time</i>:
|
||||||
|
the time it takes for a packet to get from your computer to the repeater and back.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
When the client gets a packet it didn't send,
|
||||||
|
it adds the <i>receive delay</i> to the timestamp,
|
||||||
|
and schedules to play the tones and silences in the packet
|
||||||
|
at that time.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
By adding the maximum round-trip time to the <i>longest recent transmission</i>
|
||||||
|
(the length of a dah, hopefully),
|
||||||
|
your client can make a guess about how much time needs to be added to a received timestamp,
|
||||||
|
in order to have it play back in the future at the time it comes in.
|
||||||
|
This is just a guess.
|
||||||
|
If you're communicating with somebody with a higher round-trip time than you have,
|
||||||
|
you'll need to raise your receive delay to account for it.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mdl-card mdl-shadow--4dp">
|
||||||
|
<div class="mdl-card__title">
|
||||||
|
<h2 class="mdl-card__title-text">Why do I hear a low tone?</h2>
|
||||||
|
</div>
|
||||||
|
<div class="mdl-card__supporting-text">
|
||||||
|
<p>
|
||||||
|
This is the "drop tone", and will be accompanied by an error.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
This means the packet arrived so late, it can't be played in time.
|
||||||
|
In technical terms: the timestamp of the packet plus the receive delay
|
||||||
|
is less than the current time.
|
||||||
|
It can't be scheduled to play, because we can't go back in time.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
This could be happening for three reasons:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li>You (the person hearing the drop tone) need a larger receive delay</li>
|
||||||
|
<li>The receiving computer's clock is in the future (running fast)</li>
|
||||||
|
<li>The sending computer's clock is in the past (running slow)</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Make sure your clock is synced with an Internet time server.
|
||||||
|
Accurate time is very important to how Vail works.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="mdl-card mdl-shadow--4dp">
|
<div class="mdl-card mdl-shadow--4dp">
|
||||||
<div class="mdl-card__title">
|
<div class="mdl-card__title">
|
||||||
<h2 class="mdl-card__title-text">Future plans</h2>
|
<h2 class="mdl-card__title-text">Future plans</h2>
|
||||||
|
|
|
@ -22,6 +22,29 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#errors {
|
||||||
|
color: rgba(127, 0, 0, .54);
|
||||||
|
max-height: 5em;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes yellow-fade {
|
||||||
|
0% {background: yellow;}
|
||||||
|
100% {background: none;}
|
||||||
|
}
|
||||||
|
#errors p {
|
||||||
|
margin: 0;
|
||||||
|
animation: yellow-fade 2s ease-in 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
kbd {
|
||||||
|
background-color: #eee;
|
||||||
|
border: 1px solid #bbb;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-size: 9pt;
|
||||||
|
padding: .1em .6em;
|
||||||
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
background-color: #333;
|
background-color: #333;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
@ -31,3 +54,8 @@ code {
|
||||||
img {
|
img {
|
||||||
max-width: 20em;
|
max-width: 20em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mdl-card__supporting-text {
|
||||||
|
max-height: 20em;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
|
@ -228,6 +228,10 @@ class Vail {
|
||||||
// Listen for slider values
|
// Listen for slider values
|
||||||
this.inputInit("#iambic-duration", e => this.iambic.SetInterval(e.target.value))
|
this.inputInit("#iambic-duration", e => this.iambic.SetInterval(e.target.value))
|
||||||
this.inputInit("#rx-delay", e => {this.rxDelay = Number(e.target.value)})
|
this.inputInit("#rx-delay", e => {this.rxDelay = Number(e.target.value)})
|
||||||
|
|
||||||
|
// Show what repeater we're on
|
||||||
|
let repeater = (new URL(location)).searchParams.get("repeater") || "Default"
|
||||||
|
document.querySelector("#repeater").textContent = repeater
|
||||||
}
|
}
|
||||||
|
|
||||||
inputInit(selector, func) {
|
inputInit(selector, func) {
|
||||||
|
@ -247,6 +251,17 @@ class Vail {
|
||||||
element.dispatchEvent(new Event("input"))
|
element.dispatchEvent(new Event("input"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
error(msg) {
|
||||||
|
let now = new Date()
|
||||||
|
let e = document.querySelector("#errors")
|
||||||
|
if (e) {
|
||||||
|
let p = e.appendChild(document.createElement("p"))
|
||||||
|
p.innerText = "[" + now.toLocaleTimeString() + "] " + msg
|
||||||
|
e.scrollTop = e.scrollHeight
|
||||||
|
}
|
||||||
|
this.buzzer.ErrorTone()
|
||||||
|
}
|
||||||
|
|
||||||
beginTx() {
|
beginTx() {
|
||||||
this.beginTxTime = Date.now()
|
this.beginTxTime = Date.now()
|
||||||
this.buzzer.Buzz(true)
|
this.buzzer.Buzz(true)
|
||||||
|
@ -320,7 +335,7 @@ class Vail {
|
||||||
|
|
||||||
let adjustedTxTime = beginTxTime+this.rxDelay
|
let adjustedTxTime = beginTxTime+this.rxDelay
|
||||||
if (adjustedTxTime < now) {
|
if (adjustedTxTime < now) {
|
||||||
this.buzzer.ErrorTone()
|
this.error("Packet requested playback " + (now - adjustedTxTime) + "ms in the past. Increase receive delay!")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,7 +368,7 @@ class Vail {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
this.iambic.Key(begin, DAH)
|
this.iambic.Key(begin, DAH)
|
||||||
}
|
}
|
||||||
if ((event.key == "Shift")) {
|
if ((event.code == "KeyC") || (event.code == "Comma") || (event.key == "Shift")) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
if (begin) {
|
if (begin) {
|
||||||
this.beginTx()
|
this.beginTx()
|
||||||
|
|
Loading…
Reference in New Issue