let packer add the headers

This commit is contained in:
Lewis Moten
2024-05-14 16:08:23 -04:00
parent f32380a301
commit da7feaf09e
6 changed files with 124 additions and 98 deletions

View File

@@ -5,7 +5,6 @@ class Dispatcher {
this.domain = domain; this.domain = domain;
} }
emit = (eventName, ...args) => { emit = (eventName, ...args) => {
// console.log(`${this.domain}.${eventName}`, ...args);
if(!this.LISTENERS[eventName]) return; if(!this.LISTENERS[eventName]) return;
this.LISTENERS[eventName].forEach(callback => callback(...args)); this.LISTENERS[eventName].forEach(callback => callback(...args));
} }

View File

@@ -1,4 +1,11 @@
import { bitsToBytes, bitsToInt, numberToBits, numberToBytes, numberToHex } from "./converters"; import {
bitsToBytes,
bitsToInt,
numberToBits,
numberToBytes,
numberToHex,
bytesToBits
} from "./converters";
import * as CRC from './CRC'; import * as CRC from './CRC';
let SEGMENT_DURATION = 30; let SEGMENT_DURATION = 30;
@@ -105,34 +112,42 @@ export const canSendPacket = () => {
// Make sure we have enough encoding blocks within a packet // Make sure we have enough encoding blocks within a packet
return IS_ENCODED ? maxBits >= PACKET_ENCODED_BLOCK_SIZE : true; return IS_ENCODED ? maxBits >= PACKET_ENCODED_BLOCK_SIZE : true;
} }
export const getPacketizationHeaderBitCount = () => DATA_SIZE_BITS + DATA_SIZE_CRC_BITS + DATA_CRC_BITS; export const getPacketizationHeaderBitCount = (padUnusedBits = true) => {
let count = DATA_SIZE_BITS + DATA_SIZE_CRC_BITS + DATA_CRC_BITS;
if(padUnusedBits && count % 8 !== 0) {
count += 8 - (count % 8);
}
return count;
}
export const getPacketizationHeaderByteCount = () => getPacketizationHeaderBitCount() / 8;
export const getPacketizationHeaderUnusedBitCount = () => {
return getPacketizationHeaderBitCount(true) - getPacketizationHeaderBitCount(false);
}
export const getPacketizationBitCountFromBitCount = (bitCount) => bitCount + getPacketizationHeaderBitCount(); export const getPacketizationBitCountFromBitCount = (bitCount) => bitCount + getPacketizationHeaderBitCount();
export const getPacketizationBitCountFromByteCount = (byteCount) =>
getPacketizationBitCountFromBitCount(byteCount * 8);
export const getPacketizationByteCountFromByteCount = (byteCount) =>
Math.ceil(getPacketizationBitCountFromByteCount(byteCount) / 8);
export const getPacketizationByteCountFromBitCount = bitCount =>
Math.ceil(getPacketizationBitCountFromBitCount(bitCount) / 8);
export const getDataTransferDurationMillisecondsFromByteCount = (byteCount) =>
getDataTransferDurationMilliseconds(getPacketizationBitCountFromByteCount(byteCount));
export const getDataTransferDurationSeconds = (bitCount) =>
getDataTransferDurationMilliseconds(bitCount) / 1000;
export const packetStats = byteCount => { export const packetStats = byteCount => {
const bitCount = byteCount * 8;
const packetCount = getPacketCount(bitCount); const byteCountWithHeaders = byteCount + getPacketizationHeaderByteCount();
const packetCount = Math.ceil(byteCountWithHeaders / getPacketDataByteCount());
const packetByteSize = (2 ** PACKET_SIZE_BITS);
const samplesPerPacket = Math.ceil((packetByteSize * 8) / BITS_PER_SAMPLE)
const packetDurationSeconds = (samplesPerPacket * SEGMENT_DURATION) / 1000;
const samplePeriodCount = packetCount * samplesPerPacket;
const transferBitCount = samplePeriodCount * BITS_PER_SAMPLE;
return ({ return ({
packetCount, packetCount,
sampleCount: packetCount * getPacketSegmentCount(), samplePeriodCount, // to packet utils, these are "blocks"
durationMilliseconds: packetCount * getPacketDurationMilliseconds(), transferBitCount: transferBitCount,
totalBitCount: packetCount * getPacketMaxBitCount(), transferByteCount: Math.ceil(transferBitCount / 8),
totalDurationSeconds: packetCount * packetDurationSeconds,
packetDurationSeconds,
}); });
}; };
export const getPacketCount = (bitCount) => const packetsNeededToTransferBytes = (byteCount) =>
canSendPacket() ? Math.ceil(bitCount / getPacketEncodedBitCount()) : 0; canSendPacket() ? Math.ceil(byteCount / getPacketDataByteCount()) : 0;
export const getDataTransferDurationMilliseconds = (bitCount) => export const getDataTransferDurationMilliseconds = (bitCount) =>
getPacketCount(bitCount) * getPacketDurationMilliseconds(); packetsNeededToTransferBytes(bitCount/8) * getPacketDurationMilliseconds();
export const getPacketDurationSeconds = () => getPacketDurationMilliseconds() / 1000; export const getPacketDurationSeconds = () => getPacketDurationMilliseconds() / 1000;
export const getSegmentDurationSeconds = () => getSegmentDurationMilliseconds() / 1000; export const getSegmentDurationSeconds = () => getSegmentDurationMilliseconds() / 1000;
export const getPacketSegmentCount = () => Math.ceil(getPacketMaxBitCount() / BITS_PER_SAMPLE); export const getPacketSegmentCount = () => Math.ceil(getPacketMaxBitCount() / BITS_PER_SAMPLE);
@@ -172,7 +187,58 @@ export const getPacketHeaderBitCount = (padAsBytes = true) => {
} }
return bitCount; return bitCount;
} }
export const pack = (bits) => ({ export const pack = (bytes) => {
const getHeaderBytes = () => {
// packetization headers
// data length
let dataLengthBits = [];
let dataLengthCrcBits = [];
let dataSizeCrcNumber = 0;
if(DATA_SIZE_BITS !== 0) {
dataLengthBits = numberToBits(bytes.length, DATA_SIZE_BITS);
// crc on data length
if(DATA_SIZE_CRC_BITS !== 0) {
const dataLengthBytes = bitsToBytes(dataLengthBits);
dataSizeCrcNumber = CRC.check(dataLengthBytes, DATA_SIZE_CRC_BITS);
dataLengthCrcBits = numberToBits(dataSizeCrcNumber, DATA_SIZE_CRC_BITS);
}
}
// crc on data
let dataCrcBits = [];
let dataCrcNumber = 0;
if(DATA_CRC_BITS !== 0) {
dataCrcNumber = CRC.check(bytes, DATA_CRC_BITS);
dataCrcBits = numberToBits(dataCrcNumber, DATA_CRC_BITS);
}
const headers = [
...dataLengthBits,
...dataLengthCrcBits,
...dataCrcBits
];
// pad headers to take full bytes
while(headers.length % 8 !== 0) {
headers.push(0);
}
const unusedBitCount = getPacketizationHeaderUnusedBitCount();
headers.push(...new Array(unusedBitCount).fill(0));
if(headers.length !== getPacketizationHeaderBitCount()) {
throw new Error(`Malformed header. Expected ${getPacketizationHeaderBitCount()} bits. We have ${headers.length}`);
}
// prefix bits with headers
return bitsToBytes(headers);
}
const bits = bytesToBits([...getHeaderBytes(), ...bytes]);
return ({
getBits: (packetIndex) => { getBits: (packetIndex) => {
// Returns a packet in the following order: // Returns a packet in the following order:
// - [CRC] // - [CRC]
@@ -189,6 +255,9 @@ export const pack = (bits) => ({
const startIndex = packetIndex * dataBitCount; const startIndex = packetIndex * dataBitCount;
const endIndex = startIndex + dataBitCount; const endIndex = startIndex + dataBitCount;
let packetBits = bits.slice(startIndex, endIndex); let packetBits = bits.slice(startIndex, endIndex);
if(packetBits.length === 0) {
throw new Error(`Attempted to send packet ${packetIndex}, but no data available.`)
}
if(packetBits.length % 8 !== 0) { if(packetBits.length % 8 !== 0) {
throw new Error('Attempted to create a packet with extra bits.'); throw new Error('Attempted to create a packet with extra bits.');
} }
@@ -212,14 +281,9 @@ export const pack = (bits) => ({
if(PACKET_CRC_BIT_COUNT !== 0) { if(PACKET_CRC_BIT_COUNT !== 0) {
// convert to bytes // convert to bytes
const crcCheckBits = [...headerBits, ...packetBits]; const crcCheckBits = [...headerBits, ...packetBits];
console.log('crc check bits', crcCheckBits.length) // 136 bits
const bytes = bitsToBytes(crcCheckBits); const bytes = bitsToBytes(crcCheckBits);
const crc = CRC.check(bytes, PACKET_CRC_BIT_COUNT); const crc = CRC.check(bytes, PACKET_CRC_BIT_COUNT);
const crcBits = numberToBits(crc, PACKET_CRC_BIT_COUNT); const crcBits = numberToBits(crc, PACKET_CRC_BIT_COUNT);
if(packetIndex === 0) {
console.log('header without crc was', headerBits.length)
console.log('we did crc on this', crcCheckBits.join(''))
}
// CRC must be first // CRC must be first
headerBits.unshift(...crcBits); headerBits.unshift(...crcBits);
@@ -234,6 +298,7 @@ export const pack = (bits) => ({
return encodedBits; return encodedBits;
} }
}); });
}
export const unpack = (bits) => ({ export const unpack = (bits) => ({
getPacketFromBits: (packetBits, packetIndex) => { getPacketFromBits: (packetBits, packetIndex) => {

View File

@@ -33,7 +33,7 @@ class MicrophonePanel extends BasePanel {
}) })
.catch(error => { .catch(error => {
this.error = error; this.error = error;
console.log(error); console.error(error);
this.setListening(false); this.setListening(false);
this.disconnectStream(); this.disconnectStream();
this.stopSampling(); this.stopSampling();

View File

@@ -6,7 +6,8 @@ import {
bitsToInt, bitsToInt,
bytesToBits, bytesToBits,
numberToBytes, numberToBytes,
numberToHex numberToHex,
numberToAscii
} from "./converters"; } from "./converters";
const dispatcher = new Dispatcher('StreamManager', ['change']); const dispatcher = new Dispatcher('StreamManager', ['change']);
@@ -74,13 +75,14 @@ export const applyPacket = ({
} }
if(DATA.length < length) { if(DATA.length < length) {
const copy = new Uint8ClampedArray(length); const copy = new Uint8ClampedArray(length);
copy.set(DATA.subarray(0, DATA.length)); copy.set(DATA.subarray(0, DATA.length), 0);
DATA = copy; DATA = copy;
} }
DATA.set(bytes, offset); DATA.set(bytes, offset);
delete BITS[packetIndex]; delete BITS[packetIndex];
dispatcher.emit('packetReceived'); dispatcher.emit('packetReceived');
} else { } else {
console.log("Failed", sequence);
if(!FAILED_SEQUENCES.includes(sequence)) if(!FAILED_SEQUENCES.includes(sequence))
FAILED_SEQUENCES.push(sequence); FAILED_SEQUENCES.push(sequence);
} }

View File

@@ -6,11 +6,12 @@ export const numberToBytes = (number, bitLength) => {
} }
return bytes; return bytes;
} }
export const numberToHex = (bitLength) => { export const numberToHex = (bitLength, prefix = '0x') => {
const digits = Math.ceil(bitLength / 4); const digits = Math.ceil(bitLength / 4);
return (number) => '0x' + number.toString(16).padStart(digits, '0').toUpperCase(); return (number) => prefix + Number(number).toString(16).padStart(digits, '0').toUpperCase();
} }
export const numberToAscii = (number) => String.fromCharCode(clamp(Number(number), 0, 255));
const clamp = (value, min, max) => Math.min(max, Math.max(min, value));
export function numberToBits(number, bitLength) { export function numberToBits(number, bitLength) {
const bits = []; const bits = [];
for(let i = bitLength - 1; i >= 0; i--) for(let i = bitLength - 1; i >= 0; i--)

View File

@@ -340,28 +340,32 @@ function updatePacketUtils() {
speedPanel.setMaximumDurationMilliseconds(PacketUtils.getMaxDurationMilliseconds()); speedPanel.setMaximumDurationMilliseconds(PacketUtils.getMaxDurationMilliseconds());
speedPanel.setDataBitsPerSecond(PacketUtils.getEffectiveBaud()); speedPanel.setDataBitsPerSecond(PacketUtils.getEffectiveBaud());
speedPanel.setPacketizationBitsPerSecond(PacketUtils.getBaud()); speedPanel.setPacketizationBitsPerSecond(PacketUtils.getBaud());
speedPanel.setTransferDurationMilliseconds(PacketUtils.getDataTransferDurationMillisecondsFromByteCount( const {
messagePanel.getMessageBytes().length totalDurationSeconds
)); } = PacketUtils.packetStats(messagePanel.getMessageBytes().length);
speedPanel.setTransferDurationMilliseconds(totalDurationSeconds * 1000);
} }
function updatePacketStats() { function updatePacketStats() {
const bytes = messagePanel.getMessageBytes(); const bytes = messagePanel.getMessageBytes();
const bits = bytesToBits(bytes);
const byteCount = bytes.length; const byteCount = bytes.length;
const bitCount = PacketUtils.getPacketizationBitCountFromBitCount(bits.length);;
const {
transferBitCount,
transferByteCount,
packetCount,
samplePeriodCount
} = PacketUtils.packetStats(byteCount);
// Data // Data
document.getElementById('original-byte-count').innerText = byteCount.toLocaleString(); document.getElementById('original-byte-count').innerText = byteCount.toLocaleString();
document.getElementById('packetization-byte-count').innerText = PacketUtils.getPacketizationByteCountFromBitCount(bits.length).toLocaleString(); document.getElementById('packetization-byte-count').innerText = transferByteCount.toLocaleString();
document.getElementById('packetization-bit-count').innerText = bitCount.toLocaleString(); document.getElementById('packetization-bit-count').innerText = transferBitCount.toLocaleString();
document.getElementById('packet-count').innerText = PacketUtils.getPacketCount(bitCount).toLocaleString(); document.getElementById('packet-count').innerText = packetCount.toLocaleString();
// ## Packet Encoding
// Data
document.getElementById('last-packet-unused-bit-count').innerText = PacketUtils.fromByteCountGetPacketLastUnusedBitCount(byteCount).toLocaleString(); document.getElementById('last-packet-unused-bit-count').innerText = PacketUtils.fromByteCountGetPacketLastUnusedBitCount(byteCount).toLocaleString();
document.getElementById('total-segments').innerText = samplePeriodCount.toLocaleString();
frequencyGraphPanel.setSamplePeriodsPerGroup(PacketUtils.getPacketSegmentCount()); frequencyGraphPanel.setSamplePeriodsPerGroup(PacketUtils.getPacketSegmentCount());
document.getElementById('total-segments').innerText = getTotalSegmentCount(bitCount).toLocaleString();
} }
@@ -427,46 +431,6 @@ function sendBytes(bytes) {
SENT_ORIGINAL_TEXT = bytesToText(bytes); SENT_ORIGINAL_TEXT = bytesToText(bytes);
SENT_ORIGINAL_BITS = bits.slice(); SENT_ORIGINAL_BITS = bits.slice();
// packetization headers
// data length
let dataLengthBits = [];
let dataLengthCrcBits = [];
let dataSizeCrcNumber = 0;
const dataLengthBitLength = packetizationPanel.getDataSizePower();
if(dataLengthBitLength !== 0) {
dataLengthBits = numberToBits(bytes.length, dataLengthBitLength);
// crc on data length
const dataSizeCrcBitLength = packetizationPanel.getDataSizeCrc();
if(dataSizeCrcBitLength !== 0) {
const bytes = bitsToBytes(dataLengthBits);
dataSizeCrcNumber = CRC.check(bytes, dataSizeCrcBitLength);
dataLengthCrcBits = numberToBits(dataSizeCrcNumber, dataSizeCrcBitLength);
}
}
// crc on data
let dataCrcBits = [];
const dataCrcBitLength = packetizationPanel.getDataCrc();
let dataCrcNumber = 0;
if(dataCrcBitLength !== 0) {
dataCrcNumber = CRC.check(bytes, dataCrcBitLength);
dataCrcBits = numberToBits(dataCrcNumber, dataCrcBitLength);
}
const headers = [
...dataLengthBits,
...dataLengthCrcBits,
...dataCrcBits
];
// pad headers to take full bytes
while(headers.length % 8 !== 0) {
headers.push(0);
}
// prefix bits with headers
bits.unshift(...headers);
const bitCount = bits.length;
SENT_TRANSFER_BITS.length = 0; SENT_TRANSFER_BITS.length = 0;
SENT_ENCODED_BITS.length = 0; SENT_ENCODED_BITS.length = 0;
@@ -474,11 +438,12 @@ function sendBytes(bytes) {
const startSeconds = AudioSender.now() + 0.1; const startSeconds = AudioSender.now() + 0.1;
const packetBitCount = PacketUtils.getPacketMaxBitCount(); const packetBitCount = PacketUtils.getPacketMaxBitCount();
const packetDurationSeconds = PacketUtils.getPacketDurationSeconds(); const {
const packetCount = PacketUtils.getPacketCount(bitCount); packetCount,
const totalDurationSeconds = PacketUtils.getDataTransferDurationSeconds(bitCount); totalDurationSeconds,
packetDurationSeconds
const packer = PacketUtils.pack(bits); } = PacketUtils.packetStats(byteCount);
const packer = PacketUtils.pack(bytes);
try { try {
AudioSender.beginAt(startSeconds); AudioSender.beginAt(startSeconds);
@@ -555,7 +520,7 @@ function getPacketEndMilliseconds(packetStartedMilliseconds) {
return getNextPacketStartMilliseconds(packetStartedMilliseconds) - 0.1; return getNextPacketStartMilliseconds(packetStartedMilliseconds) - 0.1;
} }
function getTotalSegmentCount(bitCount) { function getTotalSegmentCount(bitCount) {
return PacketUtils.getPacketCount(bitCount) * PacketUtils.getPacketSegmentCount(); return PacketUtils.packetsNeededToTransferBytes(bitCount/8) * PacketUtils.getPacketSegmentCount();
} }
function padArray(values, length, value) { function padArray(values, length, value) {
values = values.slice();//copy values = values.slice();//copy
@@ -598,12 +563,6 @@ function handleStreamManagerChange() {
receivePanel.setReceivedBytes(bytes); receivePanel.setReceivedBytes(bytes);
} }
} }
function parseTotalBitsTransferring() {
const dataByteCount = StreamManager.getTransferByteCount();
const bitCount = PacketUtils.getPacketizationBitCountFromByteCount(dataByteCount);
const segments = getTotalSegmentCount(bitCount);
return segments * availableFskPairsPanel.getSelectedFskPairs().length;
}
function removeEncodedPadding(bits) { function removeEncodedPadding(bits) {
const sizeBits = packetizationPanel.getDataSizePower(); const sizeBits = packetizationPanel.getDataSizePower();