//////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: CHello.cs // // Note: Simple Singularity test program. // using System; using System.Runtime.CompilerServices; using System.Threading; using Microsoft.Singularity; using Microsoft.Singularity.Directory; using Microsoft.Singularity.V1.Services; using Microsoft.Singularity.Io; namespace Microsoft.Singularity.Applications { public class CHello { public static int Main(String[] args) { Console.WriteLine("Hello World!"); ProtocolTester.UnitTest_LDPC o = new ProtocolTester.UnitTest_LDPC(); o.Run(); return 0; } } } namespace Microsoft.SPOT { /// public abstract class Trace { /// [System.Diagnostics.ConditionalAttribute("TINYCLR_TRACE")] static public void Print( string text ) { Debug.Print( text ); } } /// public abstract class Debug { static public void Print( string text ) { Console.WriteLine( text ); } static public void DumpBuffer( byte[] buf, bool fCRC, bool fOffset ) { if(buf == null) return; int offset = 0; int len = buf.Length; while(len > 0) { int row = len > 16 ? 16 : len; int i; if(fOffset) Console.Write( "{0:X8}:", offset ); for(i=0; i<16; i++) { if(i= 0x7F) c = (byte)'.'; Console.Write( "{0}", (char)c ); } offset += row; len -= row; Console.WriteLine(); } Console.WriteLine(); } } public abstract class Math { static System.Random s_rnd = new System.Random(); static public int Random( int modulo ) { return s_rnd.Next( modulo ); } } } namespace Microsoft.SPOT.Hardware { public abstract class Radio { static public void XorData( byte[]! left, byte[]! right ) { for(int i=0; i { T[]! elements; int count; public CreateNonNullArray( int n ) { this.elements = new T[n]; this.count = 0; base(); } public void InitNext( T elem ) { if(this.count < elements.Length) { this.elements[this.count++] = elem; } else { throw new InvalidOperationException( "Too many elements initialized" ); } } public T[]! GetArray() { if(count != elements.Length) { throw new InvalidOperationException("Not all elements initialized"); } return this.elements; } } public class LDPC { public static T[]![]! ConstructArray( int i, int j ) { CreateNonNullArray nna = new CreateNonNullArray( i ); for(int k=0; k < i; k++) { nna.InitNext( new T[j] ); } return nna.GetArray(); } static public byte[]![]! Solve( byte[][] dataPackets, byte[][] eccPackets, int[] eccIndex, int totalEccPackets, int totalDataPackets, int missedDataPackets, int receivedEccPackets, int pktLen ) { // dataPackets x0 = actual N - k data packets received (blanks in the missing locations) // eccPackets rhs = actual kp EC packets received // eccIndex gotec = array contains indices of EC packet received // totalEccPackets M = total length of EC stream // totalDataPackets N = total length of data stream // missedDataPackets kk = number of data packets missed // receivedEccPackets kp = number of EC packets received // AA = M * N matrix used to get the EC packets at encoder if(dataPackets == null) throw new NullReferenceException(); if(eccPackets == null) throw new NullReferenceException(); if(eccIndex == null) throw new NullReferenceException(); int maxMN = (totalEccPackets > totalDataPackets) ? totalEccPackets : totalDataPackets; bool[] pseudo = new bool[maxMN]; int i; int j; int k; for(i=0; i < maxMN; i += 5) pseudo[i] = true; for(i=0; i < maxMN; i += 7) pseudo[i] = true; for(i=0; i < maxMN; i += 13) pseudo[i] = true; for(i=0; i < maxMN; i += 17) pseudo[i] = true; for(i=0; i < maxMN; i += 19) pseudo[i] = true; for(i=0; i < maxMN; i += 33) pseudo[i] = true; for(i=0; i < maxMN; i += 37) pseudo[i] = true; //bool[][] A = new bool[receivedEccPackets][]; //for(i=0; i < receivedEccPackets; i++) //{ // A[i] = new bool[missedDataPackets]; //} // The actual matrix to be inverted (submatrix of AA) bool[]![]! A = ConstructArray( receivedEccPackets, missedDataPackets ); int[]! miss = new int[missedDataPackets + 1]; // Indices of the missing data packets int c = 0; for(i = 0; i < missedDataPackets; i++) { while(c < totalDataPackets && dataPackets[c] != null) { c++; } //Microsoft.SPOT.Debug.Print( "Missing: " + c ); miss[i] = c++; } // Get miss array miss[missedDataPackets] = -1; for(i=0; i < receivedEccPackets; i++) { byte[] t = eccPackets[i]; if(t == null) throw new NullReferenceException(); t = (byte[])t.Clone(); if(t == null) throw new NullReferenceException(); eccPackets[i] = t; // What's the actual system we have to solve for(j=0; j < missedDataPackets; j++) { int idx = eccIndex[i] + miss[j]; //A[i][j] = AA[eccIndex[i]][miss[j]]; A[i][j] = pseudo[ idx < maxMN ? idx : idx - maxMN ]; } } for(j = 0; j < totalDataPackets; j++) { byte[] dataPacket = dataPackets[j]; if(dataPacket != null) { // Packet j is not a missing packet for(i = 0; i < receivedEccPackets; i++) { int idx = eccIndex[i] + j; if(pseudo[ idx < maxMN ? idx : idx - maxMN ]) /*AA[eccIndex[i]][j]*/ { //Microsoft.SPOT.Debug.Print( "XOR: eccPackets[" + i + "], dataPackets[" + j + "]" ); byte[] eccPacket = eccPackets[i]; if(eccPacket != null) { Microsoft.SPOT.Hardware.Radio.XorData( eccPacket, dataPacket ); } } } } } //DumpMatrix( "Beginning:", A, kp, kk ); // Now set up some variables and do the LU decomposition //byte[][] y = new byte[missedDataPackets+1][]; // Intermediate solution //byte[][] xhat = new byte[missedDataPackets+1][]; // // //for(i=0; i < missedDataPackets+1; i++) //{ // y [i] = new byte[ pktLen ]; // xhat[i] = new byte[ pktLen ]; //} byte[]![]! y = ConstructArray( missedDataPackets+1, missedDataPackets+1 ); byte[]![]! xhat = ConstructArray( missedDataPackets+1, missedDataPackets+1 ); int i2; int j2; int p; //DumpMatrix( "Beginning:", A, kp, kk ); for(k = 0; k < missedDataPackets; k++) { p = k; // Find a remaining row with non-zero k-th element while(A[p][k] == false) { p++; if(p == receivedEccPackets) { //Microsoft.SPOT.Debug.Print( "Non-triangular matrix?" ); //return null; throw new Exception( "Non-triangular matrix?" ); } } if(p != k) { //Microsoft.SPOT.Debug.Print( "Swap: " + p + " " + k ); // Swap row k and row p for(j2 = 0; j2 < missedDataPackets; j2++) { bool temp = A[k][j2]; A[k][j2] = A[p][j2]; A[p][j2] = temp; } byte[] packetTemp = eccPackets[k]; eccPackets[k] = eccPackets[p]; eccPackets[p] = packetTemp; //DumpMatrix( "After:", A, kp, kk ); } for(i2 = k + 1; i2 < receivedEccPackets; i2++) { if(A[i2][k] == A[k][k]) { //Microsoft.SPOT.Debug.Print( "Mix rows: " + i2 + " " + k ); for(j2 = k + 1; j2 < missedDataPackets; j2++) { A[i2][j2] ^= A[k][j2]; } //DumpMatrix( "After:", A, kp, kk ); } } } //DumpMatrix( "After:", A, kp, kk ); ////////////////////////////////////////////////////////// // Solve Ly = Pb for(i2 = 0; i2 < missedDataPackets; i2++) { y[i2] = (byte[]!)eccPackets[i2]; for(j2 = 0; j2 < i2; j2++) { //y[i2] = (sbyte) (((y[i2] ^ (A[i2][j2] * y[j2])) & 0x000000ff)); if(A[i2][j2]) { //Microsoft.SPOT.Debug.Print( "XOR: y[" + i2 + "], y[" + j2 + "]" ); Microsoft.SPOT.Hardware.Radio.XorData( y[i2], y[j2] ); } } } // Now solve Ux = y for(i2 = missedDataPackets - 1; i2 >= 0; i2--) { xhat[i2] = y[i2]; for(j2 = i2 + 1; j2 < missedDataPackets; j2++) { //xhat[i2] = (sbyte) (((xhat[i2] ^ (A[i2][j2] * xhat[j2])) & 0x000000ff)); if(A[i2][j2]) { //Microsoft.SPOT.Debug.Print( "XOR: xhat[" + i2 + "], xhat[" + j2 + "]" ); Microsoft.SPOT.Hardware.Radio.XorData( xhat[i2], xhat[j2] ); } } } for(i2 = 0; i2 < missedDataPackets; i2++) { // Rogue value to indicate non-invertible if(A[i2][i2] == false) { //return null; throw new Exception( "Non-invertible matrix?" ); } } return xhat; } static public byte[][] GenerateEC( byte[][] dataPackets, int totalEccPackets, int totalDataPackets, int pktLen ) { int maxMN = (totalEccPackets > totalDataPackets) ? totalEccPackets : totalDataPackets; int i; int j; if(dataPackets == null) throw new NullReferenceException(); bool[] pseudo = new bool[maxMN]; for(i=0; i < maxMN; i += 5) pseudo[i] = true; for(i=0; i < maxMN; i += 7) pseudo[i] = true; for(i=0; i < maxMN; i += 13) pseudo[i] = true; for(i=0; i < maxMN; i += 17) pseudo[i] = true; for(i=0; i < maxMN; i += 19) pseudo[i] = true; for(i=0; i < maxMN; i += 33) pseudo[i] = true; for(i=0; i < maxMN; i += 37) pseudo[i] = true; byte[][] eccPackets = new byte[totalEccPackets][]; for(i=0; i < totalEccPackets; i++) { eccPackets[i] = new byte[ pktLen ]; } for(i=0; i < totalEccPackets; i++) { // Generate the EC stream for(j=0; j < totalDataPackets; j++) { //ec[i] = (sbyte) (((ec[i] ^ (AA[i][j] * x[j])) & 0x000000ff)); int idx = i + j; if(pseudo[ idx < maxMN ? idx : idx - maxMN ]) /*AA[i][j]*/ { byte[] eccPacket = eccPackets[i]; byte[] dataPacket = dataPackets[j]; if(eccPacket != null && dataPacket != null) { Microsoft.SPOT.Hardware.Radio.XorData( eccPacket, dataPacket ); } } } } return eccPackets; } } } namespace ProtocolTester { public class UnitTest_LDPC { // main program written by hpleung // Procedure: // 1. Generate Random Data Unit // 2. Generate Error Correction Unit // 3. Inject Errors in The Random Data Unit // 4. Decode // 5. Make sure after decoding data is fully received // Run it with run.exe nDataPacket nErrorCorrection nPercentageLoss nIteration // public void Run() { //for quick correctness verification Microsoft.SPOT.Debug.Print( "LPDC Test Started" ); // for(int i=0; i<100; i++) // { // RunPass( 40, 40, 40, 106 ); // } // return; for(int nPacketLength=10; nPacketLength <= 120; nPacketLength = nPacketLength + 10) { RunPass( nPacketLength, nPacketLength, 40, 106 ); } } public void RunPass( int nDataPacketCount, int nErrorCorrectionCount, int nPercentageLoss, int nPacketSize ) { byte[][] arrDataPacket = new byte[nDataPacketCount][]; byte[][] arrDataReceived = new byte[nDataPacketCount][]; byte[][] arrErrorCorrectionStream = null; int nDataLossCount = 0; int i; //randomly generate some data PopulatePacket( arrDataPacket, nPacketSize ); for(i=0; i= nPacketToLossFix) { arrDataReceived[i] = arrDataPacket[i]; } else { arrDataReceived[i] = null; } } #else int nPacketToGet = nDataPacketCount - nPacketToLossFix; while(nPacketToGet > 0) { i = Microsoft.SPOT.Math.Random( nDataPacketCount - 1 ); //Microsoft.SPOT.Debug.Print( "Picked " + i ); if(arrDataReceived[i] == null) { arrDataReceived[i] = arrDataPacket[i]; nPacketToGet--; } } #endif for(i=0; i (nDataLossCount + 5) * 100) { nErrorPacketToReceive = (int)((nDataLossCount * 108)/100) ; } else { nErrorPacketToReceive = nDataLossCount + 5; } if(nErrorPacketToReceive > nErrorCorrectionCount) { nErrorPacketToReceive = nErrorCorrectionCount; } int[]! arrECPacketReceived = new int [nErrorPacketToReceive]; byte[][] arrRHS = new byte[nErrorPacketToReceive][]; // Randomly Pick up Error Packets for(i=0; i