I think it works? Maybe?

This commit is contained in:
Neale Pickett 2020-04-26 21:43:55 -06:00
parent b202ab6968
commit 308131f901
3 changed files with 196 additions and 78 deletions

View File

@ -24,22 +24,21 @@
<div class="mdl-layout-spacer"></div> <div class="mdl-layout-spacer"></div>
<!-- Navigation --> <!-- Navigation -->
<nav class="mdl-navigation"> <nav class="mdl-navigation">
<a class="mdl-navigation__link" href="">Link</a> <a class="mdl-navigation__link" href="https://github.com/nealey/vail">Source Code</a>
<a class="mdl-navigation__link" href="">Link</a> <a class="mdl-navigation__link" href="https://github.com/nealey/vail/issues/new">Bug Report</a>
<a class="mdl-navigation__link" href="">Link</a>
<a class="mdl-navigation__link" href="">Link</a>
</nav> </nav>
</div> </div>
</header> </header>
<div class="mdl-layout__drawer"> <div class="mdl-layout__drawer">
<span class="mdl-layout-title">Title</span> <span class="mdl-layout-title">Repeaters</span>
<nav class="mdl-navigation"> <nav class="mdl-navigation">
<a class="mdl-navigation__link" href="">Link</a> <a class="mdl-navigation__link" href="?repeater=">1-15 WPM</a>
<a class="mdl-navigation__link" href="">Link</a> <a class="mdl-navigation__link" href="?repeater=int">16-20 WPM</a>
<a class="mdl-navigation__link" href="">Link</a> <a class="mdl-navigation__link" href="?repeater=adv">21-99 WPM</a>
<a class="mdl-navigation__link" href="">Link</a>
</nav> </nav>
</div> </div>
<main class="mdl-layout__content"> <main class="mdl-layout__content">
<div class="flex"> <div class="flex">
<div class="mdl-card mdl-shadow--4dp"> <div class="mdl-card mdl-shadow--4dp">
@ -54,12 +53,23 @@
<a href="#iambic" class="mdl-tabs__tab">Iambic</a> <a href="#iambic" class="mdl-tabs__tab">Iambic</a>
</div> </div>
<div class="mdl-tabs__panel is-active" id="straight"> <div class="mdl-tabs__panel is-active" id="straight">
<table class="center wide">
<tr>
<td>
<button id="key" class="key mdl-button mdl-js-button mdl-button--raised mdl-button--colored"> <button id="key" class="key mdl-button mdl-js-button mdl-button--raised mdl-button--colored">
Key Key
</button> </button>
</td>
</tr>
<tr>
<td>
<code></code>
</td>
</tr>
</table>
</div> </div>
<div class="mdl-tabs__panel" id="iambic"> <div class="mdl-tabs__panel" id="iambic">
<table style="width: 100%; text-align: center;"> <table class="center wide">
<tr> <tr>
<td> <td>
<button id="dit" class="key mdl-button mdl-js-button mdl-button--raised mdl-button--colored"> <button id="dit" class="key mdl-button mdl-js-button mdl-button--raised mdl-button--colored">
@ -74,15 +84,68 @@
</tr> </tr>
<tr> <tr>
<td> <td>
<code>.</code> or <code></code> <code>.</code> or <code>z</code>
</td> </td>
<td> <td>
<code>/</code> or <code>z</code> <code>/</code> or <code>x</code>
</td> </td>
</tr> </tr>
</table> </table>
</div>
</div>
</div>
<div class="mdl-card mdl-shadow--4dp">
<div class="mdl-card__title">
<h2 class="mdl-card__title-text">
Knobs
</h2>
</div>
<div class="mdl-card__supporting-text">
<table>
<tbody>
<tr>
<td>
Average round-trip time:
</td>
<td>
<output id="lag-value">0</output>ms
</td>
</tr>
<tr>
<td>
Longest recent transmission:
</td>
<td>
<output id="longest-rx-value">0</output>ms
</td>
</tr>
<tr>
<td>
Suggested receive delay:
</td>
<td>
<output id="suggested-delay-value">0</output>ms
</td>
</tr>
<tr>
</tr>
</tbody>
</table>
<hr>
<p> <p>
Dit length: Recieve delay:
<output id="rx-delay-value"></output>ms
<input
id="rx-delay"
class="mdl-slider mdl-js-slider"
type="range"
min="0"
max="5000"
value="300">
</p>
<p>
Dit length (iambic):
<output id="iambic-duration-value"></output>ms <output id="iambic-duration-value"></output>ms
<input <input
id="iambic-duration" id="iambic-duration"
@ -94,7 +157,6 @@
</p> </p>
</div> </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">
@ -125,32 +187,39 @@
Just like a radio repeater, Just like a radio repeater,
anybody can connect and start transmitting stuff, anybody can connect and start transmitting stuff,
and this will broadcast it to everyone connected. and this will broadcast it to everyone connected.
If there's enough interest,
I'll add something like channels.
</p> </p>
<p> <h3 class="mdl-card__title-text">Why Does This Exist?</h3>
If you need this to work on a cell phone,
let me know and I'll come up with something for you.
</p>
</div>
</div>
<div class="mdl-card mdl-shadow--4dp">
<div class="mdl-card__title">
<h2 class="mdl-card__title-text">
Why Does This Exist?
</h2>
</div>
<div class="mdl-card__supporting-text">
<p> <p>
I need a place to practice CW with actual human beings, I need a place to practice CW with actual human beings,
and I want it to be as close as possible to what I'd experience on a radio. and I want it to be as close as possible to what I'd experience on a radio.
Also, I don't want to make people buy a bunch of radio hardware. Also, I don't want to make people buy a bunch of radio hardware.
Nothing else like this exists on the Internet, as far as I can tell. Nothing else like this exists on the Internet, as far as I can tell.
</p> </p>
</div>
</div>
<h3>Who made it?</h3> <div class="mdl-card mdl-shadow--4dp">
<div class="mdl-card__title">
<h2 class="mdl-card__title-text">Future plans</h2>
</div>
<div class="mdl-card__supporting-text">
<ul>
<li>Move to a more permanent URL</li>
<li>Make this page less ugly</li>
<li>Arduino program to let you hook up an iambic paddle over USB</li>
<li>Document the protocol</li>
<li>Support multiple channels/frequencies</li>
</ul>
<h3 class="mdl-card__title-text">How can I help?</h3>
<ul>
<li>Improve the <a href="https://github.com/nealey/vail/">source code</a></li>
<li>Email me and let me know you're using it</li>
</ul>
<p> <p>
<a href="mailto:neale@woozle.org">Neale Pickett</a> kd7oqi <a href="mailto:neale@woozle.org">Neale Pickett</a> kd7oqi
@ -158,31 +227,6 @@
</div> </div>
</div> </div>
<div class="mdl-card mdl-shadow--4dp">
<div class="mdl-card__title">
<h3 class="mdl-card__title-text">Future plans</h3>
</div>
<div class="mdl-card__supporting_text">
<ul>
<li>Move to a more permanent URL</li>
<li>Make this page less ugly</li>
<li>Arduino program to let you hook up an iambic paddle over USB</li>
<li>Document the protocol</li>
<li>Support multiple channels/frequencies</li>
<li>Sensible way to make this work on a cell phone</li>
<li>Make this page less ugly (I really hate it right now)</li>
</ul>
<h3>How can I help?</h3>
<ul>
<li>Improve the <a href="https://github.com/nealey/vail/">source code</a></li>
<li><a href="mailto:neale@woozle.org">Email me</a> and let me know you're using it</li>
</ul>
</div>
</div>
</div> </div>
</main> </main>
</div> </div>

View File

@ -14,6 +14,14 @@
height: 6em; height: 6em;
} }
.center {
text-align: center;
}
.wide {
width: 100%;
}
code { code {
background-color: #333; background-color: #333;
color: #fff; color: #fff;

View File

@ -2,6 +2,7 @@
const lowFreq = 660 const lowFreq = 660
const highFreq = lowFreq * 6 / 5 // Perfect minor third const highFreq = lowFreq * 6 / 5 // Perfect minor third
const errorFreq = 30
const DIT = 1 const DIT = 1
const DAH = 3 const DAH = 3
@ -91,26 +92,26 @@ class Buzzer {
// in order to avoid "pops" (square wave overtones) // in order to avoid "pops" (square wave overtones)
// that happen with instant changes in gain. // that happen with instant changes in gain.
constructor(txGain=0.5) { constructor(txGain=0.3) {
this.txGain = txGain this.txGain = txGain
this.ac = new AudioContext() this.ac = new AudioContext()
this.lowGain = this.ac.createGain() this.lowGain = this.create(lowFreq)
this.lowGain.connect(this.ac.destination) this.highGain = this.create(highFreq)
this.lowGain.gain.value = 0 this.errorGain = this.create(errorFreq, "square")
this.lowOsc = this.ac.createOscillator() }
this.lowOsc.connect(this.lowGain)
this.lowOsc.frequency.value = lowFreq
this.lowOsc.start()
this.highGain = this.ac.createGain() create(frequency, type="sine") {
this.highGain.connect(this.ac.destination) let gain = this.ac.createGain()
this.highGain.gain.value = 0 gain.connect(this.ac.destination)
this.highOsc = this.ac.createOscillator() gain.gain.value = 0
this.highOsc.connect(this.highGain) let osc = this.ac.createOscillator()
this.highOsc.frequency.value = highFreq osc.type = type
this.highOsc.start() osc.connect(gain)
osc.frequency.value = frequency
osc.start()
return gain
} }
gain(high) { gain(high) {
@ -145,6 +146,14 @@ class Buzzer {
this.txGain = gain this.txGain = gain
} }
/**
* Play an error tone
*/
ErrorTone() {
this.errorGain.gain.setTargetAtTime(this.txGain * 0.5, this.ac.currentTime, 0.001)
this.errorGain.gain.setTargetAtTime(0, this.ac.currentTime + 0.2, 0.001)
}
/** /**
* Begin buzzing at time * Begin buzzing at time
* *
@ -187,6 +196,10 @@ class Buzzer {
class Vail { class Vail {
constructor() { constructor() {
this.sent = []
this.lagTimes = [0]
this.rxDurations = [0]
this.rxDelay = 0 // Milliseconds to add to incoming timestamps
this.beginTxTime = null // Time when we began transmitting this.beginTxTime = null // Time when we began transmitting
// Set up WebSocket // Set up WebSocket
@ -194,7 +207,7 @@ class Vail {
wsUrl.protocol = "ws:" wsUrl.protocol = "ws:"
wsUrl.pathname += "chat" wsUrl.pathname += "chat"
window.socket = new WebSocket(wsUrl) window.socket = new WebSocket(wsUrl)
window.socket.addEventListener("message", this.wsMessage) window.socket.addEventListener("message", e => this.wsMessage(e))
// Listen to HTML buttons // Listen to HTML buttons
for (let e of document.querySelectorAll("button.key")) { for (let e of document.querySelectorAll("button.key")) {
@ -213,6 +226,7 @@ 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 = e.target.value})
} }
inputInit(selector, func) { inputInit(selector, func) {
@ -241,17 +255,69 @@ class Vail {
let endTxTime = Date.now() let endTxTime = Date.now()
let duration = endTxTime - this.beginTxTime let duration = endTxTime - this.beginTxTime
this.buzzer.Silence(true) this.buzzer.Silence(true)
this.wsSend(this.beginTxTime, duration)
this.beginTxTime = null
}
let msg = JSON.stringify([this.beginTxTime, duration]) updateReading(selector, value) {
window.socket.send(msg) let e = document.querySelector(selector)
if (e) {
e.value = value
}
}
updateReadings() {
let avgLag = this.lagTimes.reduce((a,b) => (a+b)) / this.lagTimes.length
let longestRx = this.rxDurations.reduce(Math.max)
let suggestedDelay = (avgLag + longestRx) * 1.2
this.updateReading("#lag-value", avgLag.toFixed())
this.updateReading("#longest-rx-value", longestRx)
this.updateReading("#suggested-delay-value", suggestedDelay.toFixed())
}
addLagReading(duration) {
this.lagTimes.push(duration)
if (this.lagTimes.length > 20) {
this.lagTimes.shift()
}
this.updateReadings()
}
addRxDuration(duration) {
this.rxDurations.push(duration)
if (this.rxDurations.length > 20) {
this.rxDurations.shift()
}
this.updateReadings()
}
wsSend(time, duration) {
let msg = [time, duration]
let jmsg = JSON.stringify(msg)
window.socket.send(jmsg)
this.sent.push(jmsg)
} }
wsMessage(event) { wsMessage(event) {
let msg = JSON.parse(event.data) let jmsg = event.data
let msg = JSON.parse(jmsg)
let beginTxTime = msg[0] let beginTxTime = msg[0]
let duration = msg[1] let duration = msg[1]
console.log(msg) let sent = this.sent.filter(e => e != jmsg)
if (sent.length < this.sent.length) {
// We're getting our own message back, which tells us our lag.
// We shouldn't emit a tone, though.
this.sent = sent
this.addLagReading(Date.now() - beginTxTime - duration)
return
}
// Beep!
this.buzzer.BuzzDuration(false, beginTxTime+this.rxDelay, duration)
this.addRxDuration(duration)
} }
key(event) { key(event) {
@ -262,11 +328,11 @@ class Vail {
let begin = event.type.endsWith("down") let begin = event.type.endsWith("down")
if ((event.code == "Period") || (event.key == "KeyZ")) { if ((event.code == "KeyZ") || (event.code == "Period")) {
event.preventDefault() event.preventDefault()
this.iambic.Key(begin, DIT) this.iambic.Key(begin, DIT)
} }
if ((event.code == "Slash") || (event.code == "KeyX")) { if ((event.code == "KeyX") || (event.code == "Slash")) {
event.preventDefault() event.preventDefault()
this.iambic.Key(begin, DAH) this.iambic.Key(begin, DAH)
} }