Read binary serial data and parse integers
Data Acquisition

You asked:


  Is there a smarter way to accomplish the result of my code above?


So, I have another suggestion, to work on top of the suggestions by Heslacher:

Eliminate the BitConverter work. This is easily done with boolean operators (most specifically the shift operators).

short value1 = (short)((short)encoded[1] &lt;&lt; 8 | encoded[2]);
short value2 = (short)((short)encoded[3] &lt;&lt; 8 | encoded[4]);
short value3 = (short)((short)encoded[5] &lt;&lt; 8 | encoded[6]);


Why? It's fast as hell. And this tends to make it more clear what position each value represents. There's no need to place them backwards as you have to with the BitConverter. Looking at this code, it's extremely easy to determine that each pair consists of the high-byte, followed by the low-byte. With the BitConverter, the lowest byte must be followed by the subsequently higher bytes.

Can it really be faster, with all those casts, shifting (&lt;&lt;) and or's (|), and the fact that Microsoft themselves wrote the BitConverter?

You're damn right it can. Run the following programme:

byte[] encoded = new byte[7];
encoded[0] = 0xF0;
encoded[1] = 0xF1;
encoded[2] = 0xF2;
encoded[3] = 0xF3;
encoded[4] = 0xF4;
encoded[5] = 0xF5;
encoded[6] = 0xF6;

Stopwatch sw1 = new Stopwatch();

short value1 = 0, value2 = 0, value3 = 0;

sw1.Start();
for (int i = 0; i &lt; 100000000; i++)
{
    value1 = BitConverter.ToInt16(new byte[] { encoded[2], encoded[1] }, 0);
    value2 = BitConverter.ToInt16(new byte[] { encoded[4], encoded[3] }, 0);
    value3 = BitConverter.ToInt16(new byte[] { encoded[6], encoded[5] }, 0);
}
sw1.Stop();
Console.WriteLine(sw1.ElapsedTicks.ToString());
sw1.Reset();

Console.WriteLine(value1.ToString("X"));
Console.WriteLine(value2.ToString("X"));
Console.WriteLine(value3.ToString("X"));

sw1.Start();
for (int i = 0; i &lt; 100000000; i++)
{
    value1 = (short)((short)encoded[1] &lt;&lt; 8 | encoded[2]);
    value2 = (short)((short)encoded[3] &lt;&lt; 8 | encoded[4]);
    value3 = (short)((short)encoded[5] &lt;&lt; 8 | encoded[6]);
}
sw1.Stop();
Console.WriteLine(sw1.ElapsedTicks.ToString());
sw1.Reset();

Console.WriteLine(value1.ToString("X"));
Console.WriteLine(value2.ToString("X"));
Console.WriteLine(value3.ToString("X"));


Results:

12956403
F1F2
F3F4
F5F6
1505318
F1F2
F3F4
F5F6


You'll notice that the bitwise-operator method takes 12% of the time the BitConverter method does. And in this situation it makes a great deal of sense. It's easier to reason how the value1, value2 and value3 variables are being filled with the bitwise-operators. It's not so obvious with the BitConverter.

Yes, this is obviously a worst-case environment, you will likely have other bottlenecks and JITer that will influence it, but this at least goes to show that there are other just as good solutions to the same problem. Personally, I've never touched the BitConverter, I always do my own bitwise-arithmetic. To me, it's easier to read and more obvious. To you, it may not be.

I wouldn't suggest going so far as to make a loop. I did just that, and it's actually slower.

short[] myValues = new short[3];

sw1.Start();
for (int i = 0; i &lt; 100000000; i++)
{
    for (int t = 0; t &lt; myValues.Length; t++)
        myValues[t] = (short)((short)encoded[1 + t * 2] &lt;&lt; 8 | encoded[2 + t * 2]);
}
sw1.Stop();
Console.WriteLine(sw1.ElapsedTicks.ToString());
sw1.Reset();

for (int t = 0; t &lt; myValues.Length; t++)
    Console.WriteLine(myValues[t].ToString("X"));


Results:

3759655
F1F2
F3F4
F5F6


Twice the time the non-loop method took. With a dynamic List you can expect that it will be even slower. (Haven't done any experiments with that method, but one can estimate it would take longer.)

Commenting // when is too much and not enough

Another suggestion, based on his answer: put a comment on the while(SerialPort.BytesToRead &gt; 50){ line describing why we only want it if there are more than 50 bytes left to read. From your current code it's impossible to reason why.

Comments are very powerful; and though I am very liberal with my comments (placing one every 2-10 lines), you don't have to be. But they should be often enough that you don't have to examine a 200+ line file to get the relevant bits. Add minor information on where these values are used, what are they for, if you are using indices like this, then markup what each index represents. You don't have to go ape-s*** on them. Just describe what it is you are doing, and why.