decode crc-8 on packetization length

This commit is contained in:
Lewis Moten
2024-05-08 23:45:43 -04:00
parent 548cddd3f2
commit 8648e95af6
2 changed files with 75 additions and 21 deletions

View File

@@ -67,7 +67,10 @@
Error Percent: <span id="received-decoded-bits-error-percent">N/A</span>%<br /> Error Percent: <span id="received-decoded-bits-error-percent">N/A</span>%<br />
</div> </div>
<div> <div>
<h2>Decoded Text</h2> <h2>Decoded</h2>
Bytes: <span id="received-packet-original-bytes">N/A</span><br>
Length CRC-8: <span id="received-packet-original-bytes-crc">N/A</span><br>
Text:
<div class="raw-data" id="decoded-text"></div><br /> <div class="raw-data" id="decoded-text"></div><br />
</div> </div>
<div> <div>

View File

@@ -12,6 +12,7 @@ var receivedGraph;
var receivedData = []; var receivedData = [];
var MAX_AMPLITUDE = 300; // Higher than 255 to give us space var MAX_AMPLITUDE = 300; // Higher than 255 to give us space
const MAXIMUM_PACKETIZATION_SIZE_BITS = 16; const MAXIMUM_PACKETIZATION_SIZE_BITS = 16;
const CRC_BIT_COUNT = 8;
// bits after error correction is applied // bits after error correction is applied
let RECEIVED_STREAM_DECODED_BITS = []; let RECEIVED_STREAM_DECODED_BITS = [];
@@ -391,6 +392,14 @@ function calcCrc(
} }
return crc; return crc;
} }
function crc(bytes, bitCount) {
switch(bitCount) {
case 8: return crc8(bytes);
case 16: return crc16(bytes);
case 32: return crc32(bytes);
default: return 0;
}
}
function crc8(bytes) { return calcCrc(bytes, 8, 0x07); } function crc8(bytes) { return calcCrc(bytes, 8, 0x07); }
function crc16(bytes) { function crc16(bytes) {
return calcCrc( return calcCrc(
@@ -598,6 +607,7 @@ function logSent(text) {
sentDataTextArea.value += text + '\n'; sentDataTextArea.value += text + '\n';
sentDataTextArea.scrollTop = sentDataTextArea.scrollHeight; sentDataTextArea.scrollTop = sentDataTextArea.scrollHeight;
} }
function sendBytes(bytes) { function sendBytes(bytes) {
const byteCount = bytes.length; const byteCount = bytes.length;
if(byteCount === 0) { if(byteCount === 0) {
@@ -616,7 +626,13 @@ function sendBytes(bytes) {
// packetization headers // packetization headers
// data length // data length
bits.unshift(...intToBits(bytes.length, MAXIMUM_PACKETIZATION_SIZE_BITS)); const dataLengthBits = numberToBits(bytes.length, MAXIMUM_PACKETIZATION_SIZE_BITS);
// crc on data length
const dataLengthCrcBits = numberToBits(crc(bitsToBytes(dataLengthBits), CRC_BIT_COUNT), CRC_BIT_COUNT);
// prefix with headers
bits.unshift(...dataLengthBits, ...dataLengthCrcBits);
const bitCount = bits.length; const bitCount = bits.length;
SENT_TRANSFER_BITS.length = 0; SENT_TRANSFER_BITS.length = 0;
@@ -725,7 +741,7 @@ function getPacketByteCount() {
return 2 ** PACKET_SIZE_BITS; return 2 ** PACKET_SIZE_BITS;
} }
function getPacketizationBitCount(bitCount) { function getPacketizationBitCount(bitCount) {
return bitCount + MAXIMUM_PACKETIZATION_SIZE_BITS; return bitCount + MAXIMUM_PACKETIZATION_SIZE_BITS + CRC_BIT_COUNT;
} }
function getPacketBitCount() { function getPacketBitCount() {
return getPacketByteCount() * 8; return getPacketByteCount() * 8;
@@ -1141,6 +1157,19 @@ function updateReceivedData() {
...RECEIVED_PACKET_DECODED_BITS ...RECEIVED_PACKET_DECODED_BITS
] ]
// get packet data before removing decoded bits
const transmissionByteCount = parseTransmissionByteCount(allDecodedBits);
const transmissionByteCountCrc = parseTransmissionByteCountCrc(allDecodedBits)
const transmissionByteCountActualCrc = crc(
bitsToBytes(
numberToBits(
transmissionByteCount,
MAXIMUM_PACKETIZATION_SIZE_BITS
)
), CRC_BIT_COUNT
);
const trustedLength = transmissionByteCountCrc === transmissionByteCountActualCrc;
// reduce all decoded bits based on original data sent // reduce all decoded bits based on original data sent
allDecodedBits = removeDecodedHeadersAndPadding(allDecodedBits); allDecodedBits = removeDecodedHeadersAndPadding(allDecodedBits);
@@ -1184,6 +1213,13 @@ function updateReceivedData() {
HAMMING_ERROR_CORRECTION ? ERROR_CORRECTION_DATA_SIZE : 8 HAMMING_ERROR_CORRECTION ? ERROR_CORRECTION_DATA_SIZE : 8
), ),
''); '');
document.getElementById('received-packet-original-bytes').innerText = transmissionByteCount.toLocaleString();
const packetCrc = document.getElementById('received-packet-original-bytes-crc');
packetCrc.innerText = '0x' + asHex(2)(transmissionByteCountCrc);
packetCrc.className = trustedLength ? 'bit-correct' : 'bit-wrong';
if(!trustedLength) {
packetCrc.innerText += ' (Expected 0x' + asHex(2)(transmissionByteCountActualCrc) + ')';
}
document.getElementById('received-encoded-bits-error-percent').innerText = ( document.getElementById('received-encoded-bits-error-percent').innerText = (
Math.floor((1 - (correctEncodedBits / allEncodedBits.length)) * 10000) * 0.01 Math.floor((1 - (correctEncodedBits / allEncodedBits.length)) * 10000) * 0.01
@@ -1196,6 +1232,18 @@ function updateReceivedData() {
).toLocaleString(); ).toLocaleString();
document.getElementById('decoded-text').innerHTML = allDecodedBits.reduce(textExpectorReducer(SENT_ORIGINAL_TEXT), ''); document.getElementById('decoded-text').innerHTML = allDecodedBits.reduce(textExpectorReducer(SENT_ORIGINAL_TEXT), '');
} }
function asHex(length) {
return (number) => number.toString(16).padStart(length, '0').toUpperCase();
}
function parseTransmissionByteCountCrc(bits) {
const offset = MAXIMUM_PACKETIZATION_SIZE_BITS;
bits = bits.slice(offset, offset+8);
return bitsToInt(bits, 8);
}
function parseTransmissionByteCount(bits) {
bits = bits.slice(0, MAXIMUM_PACKETIZATION_SIZE_BITS);
return bitsToInt(bits, MAXIMUM_PACKETIZATION_SIZE_BITS);
}
function removeEncodedPadding(bits) { function removeEncodedPadding(bits) {
const sizeBits = MAXIMUM_PACKETIZATION_SIZE_BITS; const sizeBits = MAXIMUM_PACKETIZATION_SIZE_BITS;
const dataSize = ERROR_CORRECTION_DATA_SIZE; const dataSize = ERROR_CORRECTION_DATA_SIZE;
@@ -1212,14 +1260,17 @@ function removeEncodedPadding(bits) {
return bits; return bits;
} }
// get bits representing the size // get header bits representing the size
let dataSizeBits = []; let dataSizeBits = [];
let headerBitCount = MAXIMUM_PACKETIZATION_SIZE_BITS + CRC_BIT_COUNT;
if(HAMMING_ERROR_CORRECTION) { if(HAMMING_ERROR_CORRECTION) {
for(i = 0; i < blocksNeeded; i++) { for(i = 0; i < blocksNeeded; i++) {
const block = bits.slice(i * blockSize, (i + 1) * blockSize); const block = bits.slice(i * blockSize, (i + 1) * blockSize);
dataSizeBits.push(...hammingToNibble(block)); dataSizeBits.push(...hammingToNibble(block));
} }
dataSizeBits.length = sizeBits; dataSizeBits.length = sizeBits;
headerBitCount = Math.ceil(headerBitCount / ERROR_CORRECTION_DATA_SIZE) * ERROR_CORRECTION_BLOCK_SIZE;
} else { } else {
dataSizeBits = bits.slice(0, sizeBits); dataSizeBits = bits.slice(0, sizeBits);
} }
@@ -1227,7 +1278,7 @@ function removeEncodedPadding(bits) {
const dataByteCount = bitsToInt(dataSizeBits, sizeBits); const dataByteCount = bitsToInt(dataSizeBits, sizeBits);
// determine how many decoded bits need to be sent (including the size) // determine how many decoded bits need to be sent (including the size)
const totalBits = (dataByteCount * 8) + sizeBits; const totalBits = (dataByteCount * 8) + MAXIMUM_PACKETIZATION_SIZE_BITS + CRC_BIT_COUNT;
let encodingBitCount = totalBits; let encodingBitCount = totalBits;
if(HAMMING_ERROR_CORRECTION) { if(HAMMING_ERROR_CORRECTION) {
const blocks = Math.ceil(encodingBitCount / dataSize); const blocks = Math.ceil(encodingBitCount / dataSize);
@@ -1248,8 +1299,9 @@ function removeDecodedHeadersAndPadding(bits) {
if(bits.length >= sizeBits) { if(bits.length >= sizeBits) {
bitCount = bitsToInt(bits.slice(0, sizeBits), sizeBits); bitCount = bitsToInt(bits.slice(0, sizeBits), sizeBits);
} }
// remove size header // remove size and crc header
bits.splice(0, sizeBits); bits.splice(0, sizeBits + CRC_BIT_COUNT);
// remove excessive bits // remove excessive bits
bits.splice(bitCount * 8); bits.splice(bitCount * 8);
return bits; return bits;
@@ -1361,20 +1413,19 @@ function bitsToInt(bits, bitLength) {
// parse as int // parse as int
return parseInt(bitString, 2); return parseInt(bitString, 2);
} }
function intToBits(int, bitLength) { function intToBytes(int, bitLength) {
// max number for bit length const byteCount = Math.ceil(bitLength/8);
const max = Math.pow(2, bitLength) - 1; const bytes = [];
// overflow numbers too high for(let i = 0; i < byteCount; i++) {
const value = (int & max); bytes.push((int >> (8 * (byteCount - 1 - i))) & 0xFF);
return value }
// convert to bit string return bytes;
.toString(2) }
// prefix with zeros to fill bit length function numberToBits(number, bitLength) {
.padStart(bitLength, '0') const bits = [];
// convert to array for(let i = bitLength - 1; i >= 0; i--)
.split('') bits.push((number >> i) & 1);
// convert strings to numbers return bits;
.map(Number);
} }
function bytesToText(bytes, encoding='utf-8') { function bytesToText(bytes, encoding='utf-8') {
return new TextDecoder(encoding).decode(bytes); return new TextDecoder(encoding).decode(bytes);