public void TestEncodeFixedDualBasis() { // Create test block with data, but no parity. // Span <byte> testBlock = stackalloc byte[Rs8.BlockLength]; goodBlock.Span.Slice(0, Rs8.DataLength).CopyTo(testBlock); // Encode the test block to add parity // Rs8.Encode(testBlock, true); // Ensure the encoded output matches the expected output // // TODO: Use Span<T> overload of Assert.Equal when it is added to XUnit Assert.Equal(goodBlock.ToArray(), testBlock.ToArray()); }
private void DoTest(double corruptChance) { Span <byte> testPayload = stackalloc byte[Rs8.BlockLength]; Span <byte> corruptPayload = stackalloc byte[Rs8.BlockLength]; // Generate random data using the corrupt method at 100% // CorruptSpan(testPayload.Slice(0, Rs8.DataLength), 1, random); output.WriteLine("Test data:"); output.WriteLine(FormatSpan(testPayload)); // Calculate parity with encode // Rs8.Encode(testPayload.Slice(0, Rs8.DataLength), testPayload.Slice(Rs8.DataLength, Rs8.ParityLength)); output.WriteLine("Encoded block:"); output.WriteLine(FormatSpan(testPayload)); // Copy the test payload // testPayload.CopyTo(corruptPayload); // Corrupt the corrupt payload // CorruptSpan(corruptPayload, corruptChance, random); // Count how many bytes were actually corrupted // int corruptedByteCount = CompareSpans(testPayload, corruptPayload); output.WriteLine($"Corrupted block ({corruptedByteCount} bytes corrupted):"); output.WriteLine(FormatSpan(corruptPayload)); // Correct the corrupted array with decode // int correctedByteCount = Rs8.Decode(corruptPayload, null); // Check if there were any differences between the original // block and the corrected block // int corruptedByteCountAfterDecode = CompareSpans(testPayload, corruptPayload); output.WriteLine($"Corrected block ({correctedByteCount} bytes corrected, {corruptedByteCountAfterDecode} errors remain):"); output.WriteLine(FormatSpan(corruptPayload)); if (correctedByteCount < 0) { // Decode failed. This is expected if there were too many errors. // Check that errors were excessive. // Assert.True(corruptedByteCount > Rs8.ParityLength / 2); } else { // The decoder appears to have succeeded. // Ensure that the reported corrected bytes count // matches the number actually corrupted. // Assert.Equal(corruptedByteCount, correctedByteCount); // Verify that the block now matches the uncorrupted block // Assert.Equal(0, corruptedByteCountAfterDecode); } }
public void TestEncodeFixedSpeedProfile() { // A test block with data, but no parity. // Span <byte> testBlock = stackalloc byte[Rs8.BlockLength] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Stopwatch sw = new Stopwatch(); // Decode the test block to correct errors // int iterations = 1000; sw.Start(); for (int i = 0; i < iterations; i++) { // Encode the test block to add parity // Rs8.Encode(testBlock); } sw.Stop(); output.WriteLine($"Completed {iterations} encoder iterations, {sw.Elapsed} elapsed."); // The expected output from a known working encoder // Span <byte> correctBlock = stackalloc byte[Rs8.BlockLength] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0x2f, 0xbd, 0x4f, 0xb4, 0x74, 0x84, 0x94, 0xb9, 0xac, 0xd5, 0x54, 0x62, 0x72, 0x12, 0xee, 0xb3, 0xeb, 0xed, 0x41, 0x19, 0x1d, 0xe1, 0xd3, 0x63, 0x20, 0xea, 0x49, 0x29, 0x0b, 0x25, 0xab, 0xcf }; // Ensure the encoded output matches the expected output // Assert.True(correctBlock.SequenceEqual(testBlock)); }
public static int Main(string[] args) { bool encode = false; bool decode = false; bool verbose = false; bool veryVerbose = false; bool printInput = false; bool dualBasis = false; bool textMode = false; bool continuousMode = false; int padding = 0; int ignorePreambleCount = 0; string inputFilePath = null; string outputFilePath = null; // Parse args // if (args.Length > 0) { if (args.Contains("-h") || args.Contains("--help")) { PrintUsage(); return((int)ReturnCodes.ExOk); } verbose = args.Any(s => s.StartsWith("-v")) || args.Any(s => s.StartsWith("--verbose")); veryVerbose = args.Any(s => s.StartsWith("-vv")) || args.Any(s => s.StartsWith("--veryverbose")); if (args.Contains("-t")) { // Treat STDIN and STDOUT as hex encoded text streams. textMode = true; } else if (args.Contains("-b")) { // Treat STDIN and STDOUT as binary streams. // textMode = false; } if (args.Contains("-x")) { dualBasis = true; } if (args.Contains("-c")) { continuousMode = true; } if (args.Contains("-p")) { printInput = true; } // Get padding length // string paddingString = inputFilePath = args.SkipWhile(s => s != "-i").ElementAtOrDefault(1); if (paddingString != null) { if (!int.TryParse(paddingString, out padding)) { Console.Error.WriteLine("Invalid padding length"); return((int)ReturnCodes.ExUsage); } } // Get preamble ignore length // string ignorePreambleCountString = args.SkipWhile(s => s != "-n").ElementAtOrDefault(1); if (ignorePreambleCountString != null) { if (!int.TryParse(ignorePreambleCountString, out ignorePreambleCount)) { Console.Error.WriteLine("Invalid ignore preamble count"); return((int)ReturnCodes.ExUsage); } } // Get input file path // inputFilePath = args.SkipWhile(s => s != "-i").ElementAtOrDefault(1); if (inputFilePath == "-") { inputFilePath = null; } // Get output file path // outputFilePath = args.SkipWhile(s => s != "-o").ElementAtOrDefault(1); if (outputFilePath == "-") { outputFilePath = null; } encode = args.Contains("-e"); decode = args.Contains("-d"); if (encode && decode) { Console.Error.WriteLine("Cannot specify both encode and decode"); return((int)ReturnCodes.ExUsage); } else if (!encode && !decode) { Console.Error.WriteLine("Must specify encode or decode"); return((int)ReturnCodes.ExUsage); } } using (Stream inputStream = GetInputStream(inputFilePath)) { using (Stream outputStream = GetOutputStream(outputFilePath)) { do { // Read preamble off the input stream // if (ignorePreambleCount > 0) { if (verbose) { Console.Error.WriteLine($"Ignoring {ignorePreambleCount} bytes {(textMode ? "in hex text" : "in byte stream")}"); } ReadDummyInput(ignorePreambleCount, inputStream, textMode, veryVerbose); } if (encode) { if (verbose) { Console.Error.WriteLine($"Waiting for {Rs8.DataLength} bytes {(textMode ? "in hex text" : "in byte stream")}"); } // Alloc the block on the stack // Span <byte> block = stackalloc byte[Rs8.BlockLength]; // Read in data // try { ReadToSpan(block.Slice(0, Rs8.DataLength), inputStream, textMode, veryVerbose); } catch (Exception ex) { Console.Error.WriteLine($"Error reading from {inputFilePath ?? "stdin"}: {ex.Message}"); return((int)ReturnCodes.ExIoErr); } if (printInput) { if (verbose) { Console.Error.WriteLine("Input parsed:"); } WriteFromSpan(block, outputStream, textMode); } if (verbose) { Console.Error.WriteLine("Encoding ..."); } // Encode the block // Rs8.Encode(block, dualBasis); if (verbose) { Console.Error.WriteLine("Encoded."); } // Write output // try { WriteFromSpan(block, outputStream, textMode); } catch (Exception ex) { Console.Error.WriteLine($"Error writing to {outputFilePath ?? "stdout"}: {ex.Message}"); return((int)ReturnCodes.ExCantCreate); } } else if (decode) { if (verbose) { Console.Error.WriteLine($"Waiting for {Rs8.BlockLength} bytes {(textMode ? "in hex text" : "in byte stream")}"); } // Alloc the block on the stack // Span <byte> block = stackalloc byte[Rs8.BlockLength]; // Read in data // try { ReadToSpan(block, inputStream, textMode, veryVerbose); } catch (Exception ex) { Console.Error.WriteLine($"Error reading from {outputFilePath ?? "stdin"}: {ex.Message}"); return((int)ReturnCodes.ExIoErr); } if (printInput) { if (verbose) { Console.Error.WriteLine("Input parsed:"); } WriteFromSpan(block, outputStream, textMode); } if (verbose) { Console.Error.WriteLine("Decoding ..."); } // Decode the block, correcting errors. // int bytesCorrected = Rs8.Decode(block, null, dualBasis); // Check if the block was successfully recovered // if (bytesCorrected >= 0) { Console.Error.WriteLine($"Decoded. {bytesCorrected} errors corrected."); } else { Console.Error.WriteLine($"Unrecoverable, errors >{Rs8.ParityLength / 2}."); } // Write output // try { WriteFromSpan(block, outputStream, textMode); } catch (Exception ex) { Console.Error.WriteLine($"Error writing to {outputFilePath ?? "stdout"}: {ex.Message}"); return((int)ReturnCodes.ExCantCreate); } } else { throw new InvalidOperationException(); } }while (continuousMode); return((int)ReturnCodes.ExOk); } } }