Search code examples
c#bytearrays.net-micro-frameworknetduino

C# How to extract multiple smaller byte[] from 1 bigger byte[]?


This question is related to: C# How to extract bytes from byte array? With known starting byte

I have "100 bytes byte[]", that is composed with several "14 bytes byte[]" that occur in the bigger byte randomly.

My smaller byte[] start with the (byte) 0x55 and end 16 bytes later

I'm using the code:

        byte[] results = new byte[16];
        int index = Array.IndexOf(readBuffer, (byte)0x55, 2);
        Array.Copy(readBuffer, index, results, 0, 16);

But with this, I only get the first occurrence of my smaller byte[].

How do I get ALL the smaller byte[] blocks?

PS: I'm working with .Net Micro Framework


Solution

  • I am presuming that your message is composed of a starting cookie byte 0x55, 14 bytes of actual data, and 1 checksum byte (since you used 14 and 16 bytes interchangeably). The only way for randomly occuring subarrays to make sense is to have a checksum value at the end, to confirm your starting byte is actually a valid cookie (instead of being a data byte).

    (edited after your update)

    So, your actual data is 0x55 + 1syncbyte + 2 checksum + 12 databytes, meaning that your function should:

    Start with index i = 0 and repeat while i + 15 < input length:

    1. Check the cookie at index i.
      • If cookie is not 0x55, increment i and start again.
    2. Check the byte at index i + 1.
      • If incorrect sync byte, increment i and start again.
    3. Read the 16-bit checksum at i + 2/i + 3, calculate actual data checksum and compare.
      • If checksum doesn't match, increment i and start again.
    4. Copy bytes i + 4 to i + 15 into a segment of size 12.
      • Either yield return this result or process it right away.
    5. Increase i by 16 to skip the processed block and start again.

    You can do skip to the first occurrence of 0x55 using Array.IndexOf, but since you need to keep track of the index anyway, you may as well just do the check yourself and simplify the code (algorithmic complexity is the same O(n)).

    One way to code this would be something like:

    private static IEnumerable<byte[]> EnumerateSegments(byte[] input)
    {
        var i = 0;
        while (i + 15 < input.Length)
        {
            // check if it starts with 'sync' bytes
            // (not sure which is the second one, though?)
            var cookie = input[i];
            if (input[i] != 0x55 || input[i + 1] != 0xAA)
            {
                i++;
                continue;
            }
    
            // get the 16-bit checksum
            // (check if this is the correct endian, i.e. you
            // might need to swap bytes)
            var receivedChecksum = (input[i + 2] << 8) | (input[i + 3]);
    
            // calculate the checksum over data only
            var calculatedChecksum = CalculateChecksum(input, i + 4, 12);
            if (receivedChecksum != calculatedChecksum)
            {
                i++;
                continue;
            }
    
            // if we're here, data should be valid, so the last
            // thing left to do is to copy the data into the subarray
            var segment = new byte[12];
            Array.Copy(input, i + 4, segment, 0, 12);
            yield return segment;
    
            // skip this segment
            i += 16;
        }
    }
    

    And you would use it in a foreach loop to iterate over segments:

    foreach (var segment in EnumerateSegments(input)) 
    {
        ProcessSegment(segment);
    }
    

    Or you can get a list of segments if you want to iterate through elements several times:

    List<byte[]> listOfSegments = EnumerateSegments(input).ToList();
    

    Since you are new to C# (and generally programming), I suggest you place a breakpoint inside the method and go step by step to understand what's going on.