Add rx chart, take UI code out of keyer

This commit is contained in:
Neale Pickett 2022-04-24 19:24:56 -06:00
parent 01ed64ad2d
commit ce1579a6b8
4 changed files with 145 additions and 97 deletions

View File

@ -4,17 +4,17 @@
/**
* A chart of historical values.
*
* Curently this assumes all values are between 0 and 1,
*
* Curently this assumes all values are between 0 and 1,
* since that's all I need.
*/
class HistoryChart {
/**
* @param {Element} canvas Canvas element to draw on
* @param {string} strokeStyle strokeStyle to draw in
* @param {string} style style to draw in; falls back to the `data-style` attribute
* @param {Duration} duration Time to display history for
*/
constructor(canvas, strokeStyle="black", duration=20*Second) {
constructor(canvas, style=null, duration=20*Second) {
this.canvas = canvas
this.ctx = canvas.getContext("2d")
this.duration = duration
@ -23,13 +23,12 @@ class HistoryChart {
// One canvas pixel = 20ms
canvas.width = duration / (20 * Millisecond)
// Set origin to lower-left corner
this.ctx.scale(1, -1)
this.ctx.translate(0, -canvas.height)
this.ctx.strokeStyle = strokeStyle
this.ctx.fillStyle = strokeStyle
this.ctx.fillStyle = style || canvas.dataset.color || "black"
this.ctx.lineWdith = 2
this.running=true
@ -37,21 +36,34 @@ class HistoryChart {
}
/**
* Add an event point at a given time.
*
* These must always be added in time order.
*
* Set value to something at the current time.
*
* This also cleans up the event list,
* purging anything that is too old to be displayed.
*
* @param {Number} when Time the event happened
*
* @param {Number} value Value for the event
*/
Add(when, value) {
let now = Date.now()
let earliest = now - this.duration
Set(value) {
this.SetAt(value)
}
this.data.push([when, value])
/**
* Set value to something at the provided time.
*
* This also cleans up the event list,
* purging anything that is too old to be displayed.
*
* @param {Number} value Value for the event
* @param {Number} when Time to set the value
*/
SetAt(value, when=null) {
let now = Date.now()
if (!when) when=now
this.data.push([now, value])
this.data.sort()
let earliest = now - this.duration
// Leave one old datapoint so we know the value when the window opens
while ((this.data.length > 1) && (this.data[1][0] < earliest)) {
this.data.shift()
@ -93,4 +105,19 @@ class HistoryChart {
}
}
export {HistoryChart}
/**
* Return a new chart based on an HTML selector
*
* @param selector HTML selector
* @param style fill style
* @param duration duration of chart window
* @returns new chart, or null if it couldn't find a canvas
*/
function FromSelector(selector, style, duration=20*Second) {
let canvas = document.querySelector(selector)
if (canvas) {
return new HistoryChart(canvas, style, duration)
}
return null
}
export {HistoryChart, FromSelector}

View File

@ -95,9 +95,10 @@
<output id="note"></output>
<div id="charts">
<canvas class="chart" id="txChart"></canvas>
<canvas class="chart" id="ditChart"></canvas>
<canvas class="chart" id="dahChart"></canvas>
<canvas class="chart" id="rxChart" data-color="teal"></canvas>
<canvas class="chart" id="txChart" data-color="maroon"></canvas>
<canvas class="chart" id="ditChart" data-color="olive"></canvas>
<canvas class="chart" id="dahChart" data-color="purple"></canvas>
</div>
<div class="mdl-tabs mdl-js-tabs mdl-js-ripple-effect">

View File

@ -1,5 +1,3 @@
import * as Chart from "./chart.mjs"
/** Silent period between words */
const PAUSE_WORD = -7
/** Silent period between letters */
@ -188,25 +186,6 @@ class Keyer {
return this.last
}
/**
* Set up various charts by providing canvases for them.
*
* @param {Element} txCanvas
* @param {Element} straightCanvas
* @param {Element} ditCanvas
* @param {Element} dahCanvas
*/
SetCanvas(txCanvas=null, straightCanvas=null, ditCanvas=null, dahCanvas=null) {
for (let c of [this.txChart, this.straightChart, this.ditChart, this.dahChart]) {
if (c) c.Stop()
}
this.txChart = txCanvas?new Chart.HistoryChart(txCanvas, "red"):null
this.straightChart =straightCanvas?new Chart.HistoryChart(straightCanvas, "teal"):null
this.ditChart =ditCanvas?new Chart.HistoryChart(ditCanvas, "olive"):null
this.dahChart =dahCanvas?new Chart.HistoryChart(dahCanvas, "purple"):null
}
/**
* Return true if we are currently playing out something
*/
@ -351,9 +330,6 @@ class Keyer {
} else {
this.endTxFunc()
}
if (this.straightChart) {
this.straightChart.Add(Date.now(), down?1:0)
}
}
/**
@ -370,9 +346,6 @@ class Keyer {
this.Enqueue(DIT)
}
}
if (this.ditChart) {
this.ditChart.Add(Date.now(), down?1:0)
}
}
/**
@ -389,9 +362,6 @@ class Keyer {
this.Enqueue(DAH)
}
}
if (this.dahChart) {
this.dahChart.Add(Date.now(), down?1:0)
}
}
}

View File

@ -2,6 +2,7 @@ import * as Keyer from "./keyer.mjs"
import * as Buzzer from "./buzzer.mjs"
import * as Inputs from "./inputs.mjs"
import * as Repeaters from "./repeaters.mjs"
import * as Chart from "./chart.mjs"
const DefaultRepeater = "General"
const Millisecond = 1
@ -37,19 +38,11 @@ class VailClient {
this.lamp = new Buzzer.Lamp()
this.buzzer = new Buzzer.ToneBuzzer()
this.keyer = new Keyer.Keyer(() => this.beginTx(), () => this.endTx())
this.roboKeyer = new Keyer.Keyer(
() => {
this.buzzer.Buzz()
this.lamp.Buzz()
},
() => {
this.buzzer.Silence()
this.lamp.Silence()
}
)
this.roboKeyer = new Keyer.Keyer(() => this.Buzz(), () => this.Silence())
// Set up various input methods
this.inputs = Inputs.SetupAll(this.keyer)
// Send this as the keyer so we can intercept dit and dah events for charts
this.inputs = Inputs.SetupAll(this)
// VBand: Keep track of how the user wants the single key to behave
for (let e of document.querySelectorAll("[data-singlekey]")) {
@ -88,7 +81,6 @@ class VailClient {
this.setTelegraphBuzzer(e.target.checked)
})
this.inputInit("#timing-chart", e => {
console.log("moo")
this.setTimingCharts(e.target.checked)
})
@ -104,6 +96,88 @@ class VailClient {
document.querySelector("#muted").classList.add("hidden")
})
}
/**
* Straight key change (keyer shim)
*
* @param down If key has been depressed
*/
Straight(down) {
this.keyer.Straight(down)
if (this.straightChart) this.straightChart.Set(down?1:0)
}
/**
* Dit key change (keyer shim)
*
* @param down If the key has been depressed
*/
Dit(down) {
this.keyer.Dit(down)
if (this.ditChart) this.ditChart.Set(down?1:0)
}
/**
* Dah key change (keyer shim)
*
* @param down If the key has been depressed
*/
Dah(down) {
this.keyer.Dah(down)
if (this.dahChart) this.dahChart.Set(down?1:0)
}
Buzz() {
this.buzzer.Buzz()
this.lamp.Buzz()
if (this.rxChart) this.rxChart.Set(1)
}
Silence() {
this.buzzer.Silence()
this.lamp.Silence()
if (this.rxChart) this.rxChart.Set(0)
}
BuzzDuration(tx, when, duration) {
this.buzzer.BuzzDuration(tx, when, duration)
this.lamp.BuzzDuration(tx, when, duration)
let chart = tx?this.txChart:this.rxChart
if (chart) {
chart.SetAt(1, when)
chart.SetAt(0, when)
}
}
/**
* Start the side tone buzzer.
*
* Called from the keyer.
*/
beginTx() {
this.beginTxTime = Date.now()
this.buzzer.Buzz(true)
if (this.txChart) this.txChart.Set(1)
}
/**
* Stop the side tone buzzer, and send out how long it was active.
*
* Called from the keyer
*/
endTx() {
if (!this.beginTxTime) {
return
}
let endTxTime = Date.now()
let duration = endTxTime - this.beginTxTime
this.buzzer.Silence(true)
this.repeater.Transmit(this.beginTxTime, duration)
this.beginTxTime = null
if (this.txChart) this.txChart.Set(0)
}
/**
* Toggle timing charts.
@ -116,17 +190,17 @@ class VailClient {
let chartsContainer = document.querySelector("#charts")
if (enable) {
chartsContainer.classList.remove("hidden")
this.keyer.SetCanvas(
document.querySelector("#txChart"),
document.querySelector("#straightChart"),
document.querySelector("#ditChart"),
document.querySelector("#dahChart"),
)
this.ditChart = Chart.FromSelector("#ditChart")
this.dahChart = Chart.FromSelector("#dahChart")
this.txChart = Chart.FromSelector("#txChart")
this.rxChart = Chart.FromSelector("#rxChart")
} else {
chartsContainer.classList.add("hidden")
this.keyer.SetCanvas()
this.ditChart = null
this.dahChart = null
this.txChart = null
this.rxChart = null
}
console.log("timing chart", enable)
}
/**
@ -226,7 +300,7 @@ class VailClient {
}
/**
* Set up an input.
* Set up an HTML input element.
*
* This reads any previously saved value and sets the input value to that.
* When the input is updated, it saves the value it's updated to,
@ -263,7 +337,6 @@ class VailClient {
outputWpmElement.value = (1200 / value).toFixed(1)
}
if (callback) {
console.log("callback", selector)
callback(e)
}
})
@ -280,28 +353,6 @@ class VailClient {
this.buzzer.Error()
}
/**
* Start the side tone buzzer.
*/
beginTx() {
this.beginTxTime = Date.now()
this.buzzer.Buzz(true)
}
/**
* Stop the side tone buzzer, and send out how long it was active.
*/
endTx() {
if (!this.beginTxTime) {
return
}
let endTxTime = Date.now()
let duration = endTxTime - this.beginTxTime
this.buzzer.Silence(true)
this.repeater.Transmit(this.beginTxTime, duration)
this.beginTxTime = null
}
/**
* Called by a repeater class when there's something received.
*
@ -320,8 +371,7 @@ class VailClient {
return
}
this.buzzer.BuzzDuration(false, when, duration)
this.lamp.BuzzDuration(false, when, duration)
this.BuzzDuration(false, when, duration)
this.rxDurations.unshift(duration)
this.rxDurations.splice(20, 2)