highlight data received that does not match what was sent
This commit is contained in:
98
index.html
98
index.html
@@ -11,55 +11,83 @@
|
|||||||
<h1>Data Over Audio</h1>
|
<h1>Data Over Audio</h1>
|
||||||
<div class="panels">
|
<div class="panels">
|
||||||
<div>
|
<div>
|
||||||
Segment Duration: <input id="bit-duration-text" type="number" min="0" max="1000" value="190">ms<br>
|
<h2>Message</h2>
|
||||||
Amplitude Threshold: <input id="amplitude-threshold-text" type="number" min="0" max="100" value="75"><br>
|
|
||||||
Minimum Frequency: <input id="minimum-frequency" type="number" min="20" max="20000" value="900"><br>
|
|
||||||
Maximum Frequency: <input id="maximum-frequency" type="number" min="20" max="20000" value="1200"><br>
|
|
||||||
Last Segment Percent: <input id="last-bit-percent" type="number" min="0" max="100" value="90">%<br>
|
|
||||||
FFT Size: 2^<input id="fft-size-power-text" type="number" min="5" max="15" value="90"><br>
|
|
||||||
Frequency Resolution: <span id="frequency-resolution">N/A</span><br>
|
|
||||||
Frequency Count: <span id="frequency-count">N/A</span><br>
|
|
||||||
Frequency Resolution Multiplier: <input id="frequency-resolution-multiplier" type="number" min="1" max="10"
|
|
||||||
value="2"><br>
|
|
||||||
Smoothing Time Constant: <input id="smoothing-time-constant-text" type="number" min="0.00" max="1.00" step="0.01"
|
|
||||||
value="0.00"><br>
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" id="error-correction-hamming" checked>Hamming Code Error Correction
|
|
||||||
</label><br>
|
|
||||||
<input type="text" id="text-to-send">
|
<input type="text" id="text-to-send">
|
||||||
<button id="send-button">Send</button>
|
<button id="send-button">Send</button><br />
|
||||||
<h2>Sent</h2>
|
|
||||||
<textarea id="sent-data" rows="10" cols="40"></textarea><br />
|
<textarea id="sent-data" rows="10" cols="40"></textarea><br />
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<h2>Encoded</h2>
|
||||||
|
<textarea id="encoded-data" rows="10" cols="40"></textarea><br />
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" id="is-listening-checkbox">Listening
|
<input type="checkbox" id="is-listening-checkbox">Listening
|
||||||
</label>
|
</label>
|
||||||
<h2>Received</h2>
|
<h2>Received</h2>
|
||||||
<textarea id="received-data" rows="10" cols="40"></textarea><br />
|
<div class="raw-data" id="received-data"></div><br />
|
||||||
|
Error Percent: <span id="received-data-error-percent">N/A</span>%
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h2>Decoded</h2>
|
||||||
|
<div class="raw-data" id="decoded-data"></div><br />
|
||||||
|
Error Percent: <span id="decoded-data-error-percent">N/A</span>%<br />
|
||||||
|
Data Byte Count: <span id="decoded-byte-count">N/A</span><br />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h2>Decoded Text</h2>
|
||||||
|
<div class="raw-data" id="decoded-text"></div><br />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h2>Frequency Graph</h2>
|
||||||
|
<canvas id="received-graph" width="800" height="150"></canvas><br>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="pause-after-end" checked>Pause after end
|
||||||
|
</label><br>
|
||||||
|
Max Segments Displayed: <input id="max-bits-displayed-on-graph" type="number" min="1" max="2000"><br>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h2>Configuration</h2>
|
||||||
|
Segment Duration: <input id="bit-duration-text" type="number" min="0" max="1000" value="190">ms<br>
|
||||||
|
Amplitude Threshold: <input id="amplitude-threshold-text" type="number" min="0" max="100" value="75"><br>
|
||||||
|
Minimum Frequency: <input id="minimum-frequency" type="number" min="20" max="20000" value="900"><br>
|
||||||
|
Maximum Frequency: <input id="maximum-frequency" type="number" min="20" max="20000" value="1200"><br>
|
||||||
|
Last Segment Percent: <input id="last-bit-percent" type="number" min="0" max="100" value="90">%<br>
|
||||||
|
FFT Size: 2^<input id="fft-size-power-text" type="number" min="5" max="15" value="90"><br>
|
||||||
|
Frequency Resolution Multiplier: <input id="frequency-resolution-multiplier" type="number" min="1" max="20"
|
||||||
|
value="2"><br>
|
||||||
|
Smoothing Time Constant: <input id="smoothing-time-constant-text" type="number" min="0.00" max="1.00" step="0.01"
|
||||||
|
value="0.00"><br>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="error-correction-hamming" checked>Hamming Code Error Correction
|
||||||
|
</label><br>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h2>Packet</h2>
|
||||||
|
Data Bits: <span id="data-bits-to-send">N/A</span> Bytes: <span id="data-bytes-to-send">N/A</span><br />
|
||||||
|
Data Size Header Bits: <span id="data-size-header-bits">N/A</span><br />
|
||||||
|
Error Correction Bits: <span id="error-correction-bits">N/A</span><br />
|
||||||
|
Total Bits: <span id="total-bits-to-send">N/A</span> Bytes: <span id="total-bytes-to-send">N/A</span><br />
|
||||||
|
Channels: <span id="packet-send-channel-count">N/A</span><br />
|
||||||
|
Segment Count: <span id="packet-send-segment-count">N/A</span><br />
|
||||||
|
Segment Duration: <span id="packet-send-segment-duration">N/A</span>s<br />
|
||||||
|
Total Duration: <span id="duration-to-send">N/A</span>s<br />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h2>Information</h2>
|
||||||
|
Frequency Resolution: <span id="frequency-resolution">N/A</span><br>
|
||||||
|
Frequency Count: <span id="frequency-count">N/A</span><br>
|
||||||
Samples Per Bit: <span id="samples-per-bit">0</span><br>
|
Samples Per Bit: <span id="samples-per-bit">0</span><br>
|
||||||
Sample Rate: <span id="audio-context-sample-rate">N/A</span> per second.<br />
|
Sample Rate: <span id="audio-context-sample-rate">N/A</span> per second.<br />
|
||||||
Segments per second: <span id="durations-per-second">N/A</span><br />
|
Segments per second: <span id="durations-per-second">N/A</span><br />
|
||||||
Bits per segment: <span id="bits-per-duration">N/A</span><br />
|
Bits per segment: <span id="bits-per-duration">N/A</span><br />
|
||||||
Speed: <span id="data-transfer-speed-bits-per-second">N/A</span> Baud<br>
|
|
||||||
<span id="data-transfer-speed-bytes-per-second">N/A</span> Bytes/second<br />
|
|
||||||
Effective Speed: <span id="effective-speed-bits-per-second">N/A</span> Baud<br>
|
|
||||||
<span id="effective-speed-bytes-per-second">N/A</span> Bytes/second<br />
|
|
||||||
</div>
|
|
||||||
<canvas id="received-graph" width="550" height="100"></canvas><br>
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<h2>Decoded</h2>
|
|
||||||
<textarea id="decoded-data" rows="10" cols="40"></textarea><br />
|
|
||||||
Data Byte Count: <span id="decoded-byte-count">N/A</span><br />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label>
|
<h2>Speed</h2>
|
||||||
<input type="checkbox" id="pause-after-end" checked>Pause after end
|
Baud: <span id="data-transfer-speed-bits-per-second">N/A</span><br>
|
||||||
</label><br>
|
Bytes/s: <span id="data-transfer-speed-bytes-per-second">N/A</span><br />
|
||||||
Max Bits Displayed: <input id="max-bits-displayed-on-graph" type="number" min="1" max="2000"><br>
|
Effective Baud: <span id="effective-speed-bits-per-second">N/A</span><br>
|
||||||
|
Effective Bytes/s: <span id="effective-speed-bytes-per-second">N/A</span><br />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
155
index.js
155
index.js
@@ -36,6 +36,10 @@ var PAUSE = false;
|
|||||||
var PAUSE_AFTER_END = true;
|
var PAUSE_AFTER_END = true;
|
||||||
var PACKET_SIZE_BITS = 10;
|
var PACKET_SIZE_BITS = 10;
|
||||||
|
|
||||||
|
var EXPECTED_ENCODED_BITS = [];
|
||||||
|
var EXPECTED_BITS = [];
|
||||||
|
var EXPECTED_TEXT = '';
|
||||||
|
|
||||||
const packetBits = [];
|
const packetBits = [];
|
||||||
const packetDecodedBits = [];
|
const packetDecodedBits = [];
|
||||||
let packetDataByteCount = -1;
|
let packetDataByteCount = -1;
|
||||||
@@ -114,10 +118,35 @@ function handleWindowLoad() {
|
|||||||
// wire up events
|
// wire up events
|
||||||
sendButton.addEventListener('click', handleSendButtonClick);
|
sendButton.addEventListener('click', handleSendButtonClick);
|
||||||
isListeningCheckbox.addEventListener('click', handleListeningCheckbox);
|
isListeningCheckbox.addEventListener('click', handleListeningCheckbox);
|
||||||
// textToSend.addEventListener('keypress', handleTextToSendKeypress);
|
textToSend.addEventListener('input', handleTextToSendInput);
|
||||||
|
handleTextToSendInput();
|
||||||
showSpeed();
|
showSpeed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleTextToSendInput() {
|
||||||
|
const text = textToSend.value;
|
||||||
|
const dataByteCount = text.length;
|
||||||
|
const dataBitCount = dataByteCount * 8;
|
||||||
|
const nibblesToEncode = HAMMING_ERROR_CORRECTION ? Math.ceil((dataBitCount + PACKET_SIZE_BITS) / 4) : 0;
|
||||||
|
const errorCorrectionBits = nibblesToEncode * 3;
|
||||||
|
const totalBits = errorCorrectionBits + dataBitCount + PACKET_SIZE_BITS;
|
||||||
|
const totalBytes = Math.ceil(totalBits / 8);
|
||||||
|
const channelCount = getChannels().length;
|
||||||
|
const segmentCount = Math.ceil(totalBits / channelCount);
|
||||||
|
const totalDuration = ((segmentCount * FREQUENCY_DURATION) / 1000);
|
||||||
|
|
||||||
|
document.getElementById('error-correction-bits').innerText = errorCorrectionBits.toLocaleString();
|
||||||
|
document.getElementById('data-bytes-to-send').innerText = dataByteCount.toLocaleString();
|
||||||
|
document.getElementById('data-bits-to-send').innerText = dataBitCount.toLocaleString();
|
||||||
|
document.getElementById('total-bytes-to-send').innerText = totalBytes.toLocaleString();
|
||||||
|
document.getElementById('total-bits-to-send').innerText = totalBits.toLocaleString();
|
||||||
|
document.getElementById('duration-to-send').innerText = totalDuration.toLocaleString();
|
||||||
|
document.getElementById('packet-send-channel-count').innerText = channelCount.toLocaleString();
|
||||||
|
document.getElementById('packet-send-segment-count').innerText = segmentCount.toLocaleString();
|
||||||
|
document.getElementById('packet-send-segment-duration').innerText = (FREQUENCY_DURATION / 1000).toLocaleString();
|
||||||
|
document.getElementById('data-size-header-bits').innerText = PACKET_SIZE_BITS.toLocaleString();
|
||||||
|
}
|
||||||
|
|
||||||
function updateFrequencyResolution() {
|
function updateFrequencyResolution() {
|
||||||
const sampleRate = getAudioContext().sampleRate;
|
const sampleRate = getAudioContext().sampleRate;
|
||||||
const fftSize = 2 ** FFT_POWER;
|
const fftSize = 2 ** FFT_POWER;
|
||||||
@@ -149,6 +178,7 @@ function showSpeed() {
|
|||||||
document.getElementById('effective-speed-bits-per-second').innerText = effectiveBaud.toFixed(2);
|
document.getElementById('effective-speed-bits-per-second').innerText = effectiveBaud.toFixed(2);
|
||||||
document.getElementById('effective-speed-bytes-per-second').innerText = effectiveBytes.toFixed(2);
|
document.getElementById('effective-speed-bytes-per-second').innerText = effectiveBytes.toFixed(2);
|
||||||
}
|
}
|
||||||
|
handleTextToSendInput();
|
||||||
}
|
}
|
||||||
function nibbleToHamming(nibble) {
|
function nibbleToHamming(nibble) {
|
||||||
if(nibble.length !== 4) return [];
|
if(nibble.length !== 4) return [];
|
||||||
@@ -223,9 +253,12 @@ function sendBits(bits) {
|
|||||||
.padStart(PACKET_SIZE_BITS, '0')
|
.padStart(PACKET_SIZE_BITS, '0')
|
||||||
.split('')
|
.split('')
|
||||||
.map(Number);
|
.map(Number);
|
||||||
|
|
||||||
bits.unshift(...packetLength);
|
bits.unshift(...packetLength);
|
||||||
logSent(bits.join(''));
|
|
||||||
|
EXPECTED_BITS = bits.slice();
|
||||||
|
|
||||||
|
document.getElementById('sent-data').value = bits.reduce(bitReducer, '');
|
||||||
|
|
||||||
if(HAMMING_ERROR_CORRECTION) {
|
if(HAMMING_ERROR_CORRECTION) {
|
||||||
const encodedBits = [];
|
const encodedBits = [];
|
||||||
@@ -234,8 +267,11 @@ function sendBits(bits) {
|
|||||||
while(nibble.length < 4) nibble.push(0);
|
while(nibble.length < 4) nibble.push(0);
|
||||||
encodedBits.push(...nibbleToHamming(bits.slice(i, i + 4)));
|
encodedBits.push(...nibbleToHamming(bits.slice(i, i + 4)));
|
||||||
}
|
}
|
||||||
|
document.getElementById('encoded-data').value = encodedBits.reduce(bitReducer, '');
|
||||||
bits = encodedBits;
|
bits = encodedBits;
|
||||||
}
|
}
|
||||||
|
EXPECTED_ENCODED_BITS = bits.slice();
|
||||||
|
|
||||||
var audioContext = getAudioContext();
|
var audioContext = getAudioContext();
|
||||||
const channels = getChannels();
|
const channels = getChannels();
|
||||||
const oscillators = [];
|
const oscillators = [];
|
||||||
@@ -440,7 +476,7 @@ function processSegmentReceived() {
|
|||||||
});
|
});
|
||||||
const bitValues = channels.map(({isHigh, isLow, isMissing}) => {
|
const bitValues = channels.map(({isHigh, isLow, isMissing}) => {
|
||||||
if(isMissing > isHigh + isLow) return '.';
|
if(isMissing > isHigh + isLow) return '.';
|
||||||
return isHigh > isLow ? '1' : '0';
|
return isHigh > isLow ? 1 : 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
packetBits.push(...bitValues);
|
packetBits.push(...bitValues);
|
||||||
@@ -452,17 +488,18 @@ function processSegmentReceived() {
|
|||||||
const hamming = packetBits.slice(i, i + 7);
|
const hamming = packetBits.slice(i, i + 7);
|
||||||
const nibble = hammingToNibble(hamming);
|
const nibble = hammingToNibble(hamming);
|
||||||
packetDecodedBits.push(...nibble);
|
packetDecodedBits.push(...nibble);
|
||||||
console.log(i, hamming, nibble);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
packetDecodedBits = packetBits;
|
packetDecodedBits.length = 0;
|
||||||
|
packetDecodedBits.push(...packetBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(packetDecodedBits.length >= 10) {
|
// Determine if we can identify the length of data comming
|
||||||
// we can evaluate how many bytes are comming
|
const encodedBitsNeededForDataLength = Math.ceil(Math.ceil(PACKET_SIZE_BITS / 4) * encodingRatio);
|
||||||
const encodedBitsNeeded = Math.ceil(10 * encodingRatio);
|
if(packetDecodedBits.length >= encodedBitsNeededForDataLength) {
|
||||||
const dataLengthIndex = Math.floor(encodedBitsNeeded / channelCount);
|
// we can evaluate when we should know many bytes are comming
|
||||||
if(dataLengthIndex === segmentIndex) {
|
const dataLengthIndex = Math.floor(encodedBitsNeededForDataLength / channelCount);
|
||||||
|
// if(dataLengthIndex === segmentIndex) {
|
||||||
// we just got the bits we needed
|
// we just got the bits we needed
|
||||||
packetDataByteCount = 1 + packetDecodedBits
|
packetDataByteCount = 1 + packetDecodedBits
|
||||||
.slice(0, PACKET_SIZE_BITS)
|
.slice(0, PACKET_SIZE_BITS)
|
||||||
@@ -473,43 +510,86 @@ function processSegmentReceived() {
|
|||||||
const segments = Math.ceil(totalBits / channelCount);
|
const segments = Math.ceil(totalBits / channelCount);
|
||||||
const duration = segments * FREQUENCY_DURATION;
|
const duration = segments * FREQUENCY_DURATION;
|
||||||
const streamEnded = streamStarted + duration;
|
const streamEnded = streamStarted + duration;
|
||||||
console.log({
|
// console.log({
|
||||||
tenBitNum: packetDecodedBits
|
// tenBitNum: packetDecodedBits
|
||||||
.slice(0, PACKET_SIZE_BITS).join(''),
|
// .slice(0, PACKET_SIZE_BITS).join(''),
|
||||||
packetDataByteCount,
|
// packetDataByteCount,
|
||||||
PACKET_SIZE_BITS,
|
// PACKET_SIZE_BITS,
|
||||||
totalBits,
|
// totalBits,
|
||||||
segments,
|
// segments,
|
||||||
streamStarted,
|
// streamStarted,
|
||||||
duration,
|
// duration,
|
||||||
streamEnded
|
// streamEnded
|
||||||
});
|
// });
|
||||||
// update everyones proposed end time
|
// update everyones proposed end time
|
||||||
frequencyOverTime
|
frequencyOverTime
|
||||||
.filter(fot => fot.streamStarted === streamStarted)
|
.filter(fot => fot.streamStarted === streamStarted)
|
||||||
.forEach(fot => {
|
.forEach(fot => {
|
||||||
fot.streamEnded = streamEnded
|
fot.streamEnded = streamEnded
|
||||||
});
|
});
|
||||||
}
|
// }
|
||||||
// remove phantom bits
|
// remove phantom bits
|
||||||
const totalBits = Math.ceil(((packetDataByteCount * 8) + PACKET_SIZE_BITS) * encodingRatio);
|
// const totalBits = Math.ceil(((packetDataByteCount * 8) + PACKET_SIZE_BITS) * encodingRatio);
|
||||||
if(packetBits.length > totalBits) {
|
if(packetBits.length > totalBits) {
|
||||||
const excess = packetBits.length % totalBits;
|
// const excess = packetBits.length % totalBits;
|
||||||
packetBits.length = totalBits;
|
// packetBits.length = totalBits;
|
||||||
bitValues.length = bitValues.length - excess;
|
// bitValues.length = bitValues.length - excess;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('decoded-data').value = packetDecodedBits.reduce((all, bit, i) => {
|
document.getElementById('decoded-data').innerHTML = packetDecodedBits.reduce(bitExpectorReducer(EXPECTED_BITS), '');
|
||||||
if(i !== 0 && i % 8 === 0) return all + ' ' + bit;
|
document.getElementById('received-data').innerHTML = packetBits.reduce(bitExpectorReducer(EXPECTED_ENCODED_BITS), '');
|
||||||
return all + bit;
|
|
||||||
}, '');
|
const encodedBitCount = EXPECTED_ENCODED_BITS.length;
|
||||||
document.getElementById('received-data').value = packetBits.reduce((all, bit, i) => {
|
const decodedBitCount = EXPECTED_BITS.length;
|
||||||
if(i !== 0 && i % 8 === 0) return all + ' ' + bit;
|
const correctEncodedBits = packetBits.filter((b, i) => i < encodedBitCount && b === EXPECTED_ENCODED_BITS[i]).length;
|
||||||
return all + bit;
|
const correctedDecodedBits = packetDecodedBits.filter((b, i) => i < decodedBitCount && b === EXPECTED_BITS[i]).length;
|
||||||
}, '');
|
document.getElementById('received-data-error-percent').innerText = (
|
||||||
|
Math.floor((1 - (correctEncodedBits / encodedBitCount)) * 1000) * 0.1
|
||||||
|
).toLocaleString();
|
||||||
|
document.getElementById('decoded-data-error-percent').innerText = (
|
||||||
|
Math.floor((1 - (correctedDecodedBits / decodedBitCount)) * 1000) * 0.1
|
||||||
|
).toLocaleString();
|
||||||
|
document.getElementById('decoded-text').innerHTML = packetDecodedBits.reduce(textExpectorReducer(EXPECTED_TEXT), '');
|
||||||
}
|
}
|
||||||
|
function bitReducer(all, bit, i) {
|
||||||
|
if(i !== 0 && i % 8 === 0) return all + ' ' + bit;
|
||||||
|
return all + bit;
|
||||||
|
}
|
||||||
|
const bitExpectorReducer = expected => (all, bit, i) => {
|
||||||
|
// if(i === 0) console.log(expected.slice(), all, bit, i);
|
||||||
|
|
||||||
|
if(i !== 0 && i % 8 === 0) all += ' ';
|
||||||
|
if(i >= expected.length) {
|
||||||
|
all += '<span class="bit-unexpected">';
|
||||||
|
} else if(expected[i] !== bit) {
|
||||||
|
all += '<span class="bit-wrong">';
|
||||||
|
}
|
||||||
|
all += bit;
|
||||||
|
if(i >= expected.length || expected[i] !== bit) {
|
||||||
|
all += '</span>';
|
||||||
|
}
|
||||||
|
return all;
|
||||||
|
}
|
||||||
|
const textExpectorReducer = expected => (all, bit, i, bits) => {
|
||||||
|
if(i < PACKET_SIZE_BITS) return all;
|
||||||
|
if((i - PACKET_SIZE_BITS) % 8 === 0) {
|
||||||
|
const bitString = bits.slice(
|
||||||
|
i,
|
||||||
|
i + 8
|
||||||
|
).join('').padEnd(8, '0');
|
||||||
|
const ascii = parseInt(bitString, 2);
|
||||||
|
const char = String.fromCharCode(ascii);
|
||||||
|
const charIndex = Math.floor((i - PACKET_SIZE_BITS) / 8);
|
||||||
|
if(char !== expected[charIndex]) {
|
||||||
|
all += '<span class="bit-wrong">' + char + '</span>';
|
||||||
|
} else {
|
||||||
|
all += char;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return all;
|
||||||
|
}
|
||||||
|
|
||||||
function resetGraphData() {
|
function resetGraphData() {
|
||||||
frequencyOverTime.length = 0;
|
frequencyOverTime.length = 0;
|
||||||
bitStart.length = 0;
|
bitStart.length = 0;
|
||||||
@@ -552,6 +632,7 @@ function handleSendButtonClick() {
|
|||||||
sentDataTextArea.value = '';
|
sentDataTextArea.value = '';
|
||||||
|
|
||||||
const text = document.getElementById('text-to-send').value;
|
const text = document.getElementById('text-to-send').value;
|
||||||
|
EXPECTED_TEXT = text;
|
||||||
sendBits(textToBits(text));
|
sendBits(textToBits(text));
|
||||||
}
|
}
|
||||||
function handleListeningCheckbox(e) {
|
function handleListeningCheckbox(e) {
|
||||||
@@ -761,7 +842,7 @@ function drawFrequencyData() {
|
|||||||
ctx.moveTo(0, thresholdY);
|
ctx.moveTo(0, thresholdY);
|
||||||
ctx.lineTo(width, thresholdY);
|
ctx.lineTo(width, thresholdY);
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
drawBitDurationLines(ctx, 'yellow');
|
drawBitDurationLines(ctx, 'rgba(255, 255, 0, .25)');
|
||||||
drawBitStart(ctx, 'green');
|
drawBitStart(ctx, 'green');
|
||||||
const frequencies = getChannels();
|
const frequencies = getChannels();
|
||||||
frequencies.forEach(([low, high], i) => {
|
frequencies.forEach(([low, high], i) => {
|
||||||
|
|||||||
18
style.css
18
style.css
@@ -18,7 +18,23 @@ body {
|
|||||||
border-bottom: 4px solid darkolivegreen;
|
border-bottom: 4px solid darkolivegreen;
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
.panels > div textarea {
|
#received-graph {
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
textarea, .raw-data {
|
||||||
background-color: rgb(41, 59, 10);
|
background-color: rgb(41, 59, 10);
|
||||||
color: rgb(75, 185, 75);
|
color: rgb(75, 185, 75);
|
||||||
|
width: 250px;
|
||||||
|
height: 75px;
|
||||||
|
font-size: x-small;
|
||||||
|
border: 1px solid grey;
|
||||||
|
overflow: auto;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
.bit-wrong {
|
||||||
|
font-weight: bolder;
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
.bit-unexpected {
|
||||||
|
color: green;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user