1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Diagnostics;
6 using System.IO.PortsTests;
7 using System.Threading;
8 using Legacy.Support;
9 using Xunit;
10 
11 namespace System.IO.Ports.Tests
12 {
13     public class Parity_Property : PortsTest
14     {
15         //The default number of bytes to read/write to verify the speed of the port
16         //and that the bytes were transfered successfully
17         private const int DEFAULT_BYTE_SIZE = 512;
18 
19         //If the percentage difference between the expected time to transfer with the specified parity
20         //and the actual time found through Stopwatch is greater then 10% then the Parity value was not correctly
21         //set and the testcase fails.
22         private const double MAX_ACCEPTABEL_PERCENTAGE_DIFFERENCE = .10;
23 
24         //The default number of databits to use when testing Parity
25         private const int DEFUALT_DATABITS = 8;
26         private const int NUM_TRYS = 3;
27 
28         private enum ThrowAt { Set, Open };
29 
30         #region Test Cases
31         [ConditionalFact(nameof(HasNullModem))]
Parity_Default()32         public void Parity_Default()
33         {
34             using (SerialPort com1 = new SerialPort(TCSupport.LocalMachineSerialInfo.FirstAvailablePortName))
35             {
36                 SerialPortProperties serPortProp = new SerialPortProperties();
37 
38                 Debug.WriteLine("Verifying default Parity");
39 
40                 serPortProp.SetAllPropertiesToOpenDefaults();
41                 serPortProp.SetProperty("PortName", TCSupport.LocalMachineSerialInfo.FirstAvailablePortName);
42                 com1.Open();
43 
44                 serPortProp.VerifyPropertiesAndPrint(com1);
45                 VerifyParity(com1, DEFAULT_BYTE_SIZE);
46 
47                 serPortProp.VerifyPropertiesAndPrint(com1);
48             }
49         }
50 
51         [ConditionalFact(nameof(HasNullModem))]
Parity_None_BeforeOpen()52         public void Parity_None_BeforeOpen()
53         {
54             Debug.WriteLine("Verifying None Parity before open");
55             VerifyParityBeforeOpen((int)Parity.None, DEFAULT_BYTE_SIZE);
56         }
57 
58         [ConditionalFact(nameof(HasNullModem))]
Parity_Even_BeforeOpen()59         public void Parity_Even_BeforeOpen()
60         {
61             Debug.WriteLine("Verifying Even Parity before open");
62             VerifyParityBeforeOpen((int)Parity.Even, DEFAULT_BYTE_SIZE);
63         }
64 
65 
66         [ConditionalFact(nameof(HasNullModem))]
Parity_Odd_BeforeOpen()67         public void Parity_Odd_BeforeOpen()
68         {
69             Debug.WriteLine("Verifying Odd Parity before open");
70             VerifyParityBeforeOpen((int)Parity.Odd, DEFAULT_BYTE_SIZE);
71         }
72 
73         [ConditionalFact(nameof(HasNullModem))]
Parity_Mark_BeforeOpen()74         public void Parity_Mark_BeforeOpen()
75         {
76             Debug.WriteLine("Verifying Mark Parity before open");
77             VerifyParityBeforeOpen((int)Parity.Mark, DEFAULT_BYTE_SIZE);
78         }
79 
80         [ConditionalFact(nameof(HasNullModem))]
Parity_Space_BeforeOpen()81         public void Parity_Space_BeforeOpen()
82         {
83             Debug.WriteLine("Verifying Space before open");
84             VerifyParityBeforeOpen((int)Parity.Space, DEFAULT_BYTE_SIZE);
85         }
86 
87         [ConditionalFact(nameof(HasNullModem))]
Parity_None_AfterOpen()88         public void Parity_None_AfterOpen()
89         {
90             Debug.WriteLine("Verifying None Parity after open");
91             VerifyParityAfterOpen((int)Parity.None, DEFAULT_BYTE_SIZE);
92         }
93 
94         [ConditionalFact(nameof(HasNullModem))]
Parity_Even_AfterOpen()95         public void Parity_Even_AfterOpen()
96         {
97             Debug.WriteLine("Verifying Even Parity after open");
98             VerifyParityAfterOpen((int)Parity.Even, DEFAULT_BYTE_SIZE);
99         }
100 
101         [ConditionalFact(nameof(HasNullModem))]
Parity_Odd_AfterOpen()102         public void Parity_Odd_AfterOpen()
103         {
104             Debug.WriteLine("Verifying Odd Parity after open");
105             VerifyParityAfterOpen((int)Parity.Odd, DEFAULT_BYTE_SIZE);
106         }
107 
108         [ConditionalFact(nameof(HasNullModem))]
Parity_Mark_AfterOpen()109         public void Parity_Mark_AfterOpen()
110         {
111             Debug.WriteLine("Verifying Mark Parity after open");
112             VerifyParityAfterOpen((int)Parity.Mark, DEFAULT_BYTE_SIZE);
113         }
114 
115         [ConditionalFact(nameof(HasNullModem))]
Parity_Space_AfterOpen()116         public void Parity_Space_AfterOpen()
117         {
118             Debug.WriteLine("Verifying Space Parity after open");
119             VerifyParityAfterOpen((int)Parity.Space, DEFAULT_BYTE_SIZE);
120         }
121 
122         [ConditionalFact(nameof(HasOneSerialPort))]
Parity_Int32MinValue()123         public void Parity_Int32MinValue()
124         {
125             Debug.WriteLine("Verifying Int32.MinValue Parity");
126             VerifyException(int.MinValue, ThrowAt.Set, typeof(ArgumentOutOfRangeException));
127         }
128 
129         [ConditionalFact(nameof(HasOneSerialPort))]
Parity_Neg1()130         public void Parity_Neg1()
131         {
132             Debug.WriteLine("Verifying -1 Parity");
133             VerifyException(-1, ThrowAt.Set, typeof(ArgumentOutOfRangeException));
134         }
135 
136         [ConditionalFact(nameof(HasOneSerialPort))]
Parity_Int32MaxValue()137         public void Parity_Int32MaxValue()
138         {
139             Debug.WriteLine("Verifying Int32.MaxValue Parity");
140             VerifyException(int.MaxValue, ThrowAt.Set, typeof(ArgumentOutOfRangeException));
141         }
142 
143         [ConditionalFact(nameof(HasNullModem))]
Parity_Even_Odd()144         public void Parity_Even_Odd()
145         {
146             using (SerialPort com1 = new SerialPort(TCSupport.LocalMachineSerialInfo.FirstAvailablePortName))
147             {
148                 SerialPortProperties serPortProp = new SerialPortProperties();
149 
150                 Debug.WriteLine("Verifying Parity Even and then Odd");
151 
152                 serPortProp.SetAllPropertiesToOpenDefaults();
153                 serPortProp.SetProperty("PortName", TCSupport.LocalMachineSerialInfo.FirstAvailablePortName);
154                 com1.Open();
155                 com1.Parity = Parity.Even;
156                 com1.Parity = Parity.Odd;
157                 serPortProp.SetProperty("Parity", Parity.Odd);
158 
159                 serPortProp.VerifyPropertiesAndPrint(com1);
160                 VerifyParity(com1, DEFAULT_BYTE_SIZE);
161 
162                 serPortProp.VerifyPropertiesAndPrint(com1);
163             }
164         }
165 
166         [ConditionalFact(nameof(HasNullModem))]
Parity_Odd_Even()167         public void Parity_Odd_Even()
168         {
169             using (SerialPort com1 = new SerialPort(TCSupport.LocalMachineSerialInfo.FirstAvailablePortName))
170             {
171                 SerialPortProperties serPortProp = new SerialPortProperties();
172 
173                 Debug.WriteLine("Verifying Parity Odd and then Even");
174 
175                 serPortProp.SetAllPropertiesToOpenDefaults();
176                 serPortProp.SetProperty("PortName", TCSupport.LocalMachineSerialInfo.FirstAvailablePortName);
177                 com1.Open();
178                 com1.Parity = Parity.Odd;
179                 com1.Parity = Parity.Even;
180                 serPortProp.SetProperty("Parity", Parity.Even);
181 
182                 serPortProp.VerifyPropertiesAndPrint(com1);
183                 VerifyParity(com1, DEFAULT_BYTE_SIZE);
184 
185                 serPortProp.VerifyPropertiesAndPrint(com1);
186             }
187         }
188 
189         [ConditionalFact(nameof(HasNullModem))]
Parity_Odd_Mark()190         public void Parity_Odd_Mark()
191         {
192             using (SerialPort com1 = new SerialPort(TCSupport.LocalMachineSerialInfo.FirstAvailablePortName))
193             {
194                 SerialPortProperties serPortProp = new SerialPortProperties();
195 
196                 Debug.WriteLine("Verifying Parity Odd and then Mark");
197 
198                 serPortProp.SetAllPropertiesToOpenDefaults();
199                 serPortProp.SetProperty("PortName", TCSupport.LocalMachineSerialInfo.FirstAvailablePortName);
200                 com1.Open();
201                 com1.Parity = Parity.Odd;
202                 com1.Parity = Parity.Mark;
203                 serPortProp.SetProperty("Parity", Parity.Mark);
204 
205                 serPortProp.VerifyPropertiesAndPrint(com1);
206                 VerifyParity(com1, DEFAULT_BYTE_SIZE);
207 
208                 serPortProp.VerifyPropertiesAndPrint(com1);
209             }
210         }
211         #endregion
212 
213         #region Verification for Test Cases
VerifyException(int parity, ThrowAt throwAt, Type expectedException)214         private void VerifyException(int parity, ThrowAt throwAt, Type expectedException)
215         {
216             using (SerialPort com = new SerialPort(TCSupport.LocalMachineSerialInfo.FirstAvailablePortName))
217             {
218                 VerifyExceptionAtOpen(com, parity, throwAt, expectedException);
219                 if (com.IsOpen)
220                     com.Close();
221 
222                 VerifyExceptionAfterOpen(com, parity, expectedException);
223             }
224         }
225 
226 
VerifyExceptionAtOpen(SerialPort com, int parity, ThrowAt throwAt, Type expectedException)227         private void VerifyExceptionAtOpen(SerialPort com, int parity, ThrowAt throwAt, Type expectedException)
228         {
229             int origParity = (int)com.Parity;
230             SerialPortProperties serPortProp = new SerialPortProperties();
231 
232             serPortProp.SetAllPropertiesToDefaults();
233             serPortProp.SetProperty("PortName", TCSupport.LocalMachineSerialInfo.FirstAvailablePortName);
234 
235             if (ThrowAt.Open == throwAt)
236                 serPortProp.SetProperty("Parity", (Parity)parity);
237 
238             try
239             {
240                 com.Parity = (Parity)parity;
241 
242                 if (ThrowAt.Open == throwAt)
243                     com.Open();
244 
245                 if (null != expectedException)
246                 {
247                     Fail("ERROR!!! Expected Open() to throw {0} and nothing was thrown", expectedException);
248                 }
249             }
250             catch (Exception e)
251             {
252                 if (null == expectedException)
253                 {
254                     Fail("ERROR!!! Expected Open() NOT to throw an exception and {0} was thrown", e.GetType());
255                 }
256                 else if (e.GetType() != expectedException)
257                 {
258                     Fail("ERROR!!! Expected Open() throw {0} and {1} was thrown", expectedException, e.GetType());
259                 }
260             }
261 
262             serPortProp.VerifyPropertiesAndPrint(com);
263             com.Parity = (Parity)origParity;
264         }
265 
VerifyExceptionAfterOpen(SerialPort com, int parity, Type expectedException)266         private void VerifyExceptionAfterOpen(SerialPort com, int parity, Type expectedException)
267         {
268             SerialPortProperties serPortProp = new SerialPortProperties();
269 
270             com.Open();
271             serPortProp.SetAllPropertiesToOpenDefaults();
272             serPortProp.SetProperty("PortName", TCSupport.LocalMachineSerialInfo.FirstAvailablePortName);
273 
274             try
275             {
276                 com.Parity = (Parity)parity;
277                 if (null != expectedException)
278                 {
279                     Fail("ERROR!!! Expected setting the Parity after Open() to throw {0} and nothing was thrown", expectedException);
280                 }
281             }
282             catch (Exception e)
283             {
284                 if (null == expectedException)
285                 {
286                     Fail("ERROR!!! Expected setting the Parity after Open() NOT to throw an exception and {0} was thrown", e.GetType());
287                 }
288                 else if (e.GetType() != expectedException)
289                 {
290                     Fail("ERROR!!! Expected setting the Parity after Open() throw {0} and {1} was thrown", expectedException, e.GetType());
291                 }
292             }
293 
294             serPortProp.VerifyPropertiesAndPrint(com);
295         }
296 
297 
VerifyParityBeforeOpen(int parity, int numBytesToSend)298         private void VerifyParityBeforeOpen(int parity, int numBytesToSend)
299         {
300             using (SerialPort com1 = new SerialPort(TCSupport.LocalMachineSerialInfo.FirstAvailablePortName))
301             {
302                 SerialPortProperties serPortProp = new SerialPortProperties();
303 
304                 serPortProp.SetAllPropertiesToOpenDefaults();
305                 serPortProp.SetProperty("PortName", TCSupport.LocalMachineSerialInfo.FirstAvailablePortName);
306 
307                 com1.Parity = (Parity)parity;
308                 com1.Open();
309                 serPortProp.SetProperty("Parity", (Parity)parity);
310 
311                 serPortProp.VerifyPropertiesAndPrint(com1);
312                 VerifyParity(com1, numBytesToSend);
313                 serPortProp.VerifyPropertiesAndPrint(com1);
314             }
315         }
316 
317 
VerifyParityAfterOpen(int parity, int numBytesToSend)318         private void VerifyParityAfterOpen(int parity, int numBytesToSend)
319         {
320             using (SerialPort com1 = new SerialPort(TCSupport.LocalMachineSerialInfo.FirstAvailablePortName))
321             {
322                 SerialPortProperties serPortProp = new SerialPortProperties();
323 
324                 serPortProp.SetAllPropertiesToOpenDefaults();
325                 serPortProp.SetProperty("PortName", TCSupport.LocalMachineSerialInfo.FirstAvailablePortName);
326 
327                 com1.Open();
328                 com1.Parity = (Parity)parity;
329                 serPortProp.SetProperty("Parity", (Parity)parity);
330 
331                 serPortProp.VerifyPropertiesAndPrint(com1);
332                 VerifyParity(com1, numBytesToSend);
333                 serPortProp.VerifyPropertiesAndPrint(com1);
334             }
335         }
336 
VerifyParity(SerialPort com1, int numBytesToSend)337         private void VerifyParity(SerialPort com1, int numBytesToSend)
338         {
339             VerifyParity(com1, numBytesToSend, DEFUALT_DATABITS);
340         }
341 
VerifyParity(SerialPort com1, int numBytesToSend, int dataBits)342         private void VerifyParity(SerialPort com1, int numBytesToSend, int dataBits)
343         {
344             byte[] xmitBytes = new byte[numBytesToSend];
345             byte[] expectedBytes = new byte[numBytesToSend];
346             Random rndGen = new Random();
347             using (SerialPort com2 = new SerialPort(TCSupport.LocalMachineSerialInfo.SecondAvailablePortName))
348             {
349                 byte shiftMask = 0xFF;
350 
351                 //Create a mask that when logicaly and'd with the transmitted byte will
352                 //will result in the byte recievied due to the leading bits being chopped
353                 //off due to Parity less then 8
354                 if (8 > dataBits)
355                     shiftMask >>= 8 - com1.DataBits;
356 
357                 //Generate some random bytes to read/write for this Parity setting
358                 for (int i = 0; i < xmitBytes.Length; i++)
359                 {
360                     xmitBytes[i] = (byte)rndGen.Next(0, 256);
361                     expectedBytes[i] = (byte)(xmitBytes[i] & shiftMask);
362                 }
363 
364                 com2.DataBits = dataBits;
365                 com2.Parity = com1.Parity;
366                 com1.DataBits = dataBits;
367                 com2.Open();
368 
369                 PerformWriteRead(com1, com2, xmitBytes, expectedBytes);
370             }
371         }
372 
373 
VerifyReadParity(int parity, int dataBits, int numBytesToSend)374         private void VerifyReadParity(int parity, int dataBits, int numBytesToSend)
375         {
376             byte[] xmitBytes = new byte[numBytesToSend];
377             byte[] expectedBytes = new byte[numBytesToSend];
378             Random rndGen = new Random();
379             using (SerialPort com1 = new SerialPort(TCSupport.LocalMachineSerialInfo.FirstAvailablePortName))
380             using (SerialPort com2 = new SerialPort(TCSupport.LocalMachineSerialInfo.SecondAvailablePortName))
381             {
382                 byte shiftMask = 0xFF;
383                 bool parityErrorOnLastByte = false, isParityError = false;
384                 int parityIndex;
385                 byte parityErrorByte;
386 
387                 if (8 > dataBits)
388                     com1.DataBits = dataBits + 1;
389                 else
390                     com1.Parity = (Parity)parity;
391 
392                 com2.Parity = (Parity)parity;
393                 com2.DataBits = dataBits;
394                 com1.StopBits = StopBits.One;
395                 com2.StopBits = StopBits.One;
396 
397                 //Create a mask that when logicaly and'd with the transmitted byte will
398                 //will result in the byte recievied due to the leading bits being chopped
399                 //off due to Parity less then 8
400                 shiftMask >>= 8 - dataBits;
401 
402                 //Generate some random bytes to read/write for this Parity setting
403                 for (int i = 0; i < xmitBytes.Length; i++)
404                 {
405                     do
406                     {
407                         xmitBytes[i] = (byte)rndGen.Next(0, 256);
408                         isParityError = !VerifyParityByte(xmitBytes[i], com1.DataBits, (Parity)parity);
409                     } while (isParityError); //Prevent adacent parity errors see VSWhidbey 103979
410 
411                     expectedBytes[i] = (byte)(xmitBytes[i] & shiftMask);
412                     parityErrorOnLastByte = isParityError;
413                 }
414 
415                 do
416                 {
417                     parityErrorByte = (byte)rndGen.Next(0, 256);
418                     isParityError = !VerifyParityByte(parityErrorByte, com1.DataBits, (Parity)parity);
419                 } while (!isParityError);
420 
421                 parityIndex = rndGen.Next(xmitBytes.Length / 4, xmitBytes.Length / 2);
422                 xmitBytes[parityIndex] = parityErrorByte;
423                 expectedBytes[parityIndex] = com2.ParityReplace;
424 
425                 Debug.WriteLine("parityIndex={0}", parityIndex);
426 
427                 parityIndex = rndGen.Next((3 * xmitBytes.Length) / 4, xmitBytes.Length - 1);
428                 xmitBytes[parityIndex] = parityErrorByte;
429                 expectedBytes[parityIndex] = com2.ParityReplace;
430 
431                 Debug.WriteLine("parityIndex={0}", parityIndex);
432 
433                 /*
434                 for(int i=0; i<xmitBytes.Length; i++) {
435                   do {
436                     xmitBytes[i] = (byte)rndGen.Next(0, 256);
437                     isParityError = !VerifyParityByte(xmitBytes[i], com1.DataBits, (Parity)parity);
438                   }while(parityErrorOnLastByte && isParityError); //Prevent adacent parity errors see VSWhidbey 103979
439 
440                   expectedBytes[i] =  isParityError ? com2.ParityReplace :(byte)(xmitBytes[i] & shiftMask);
441                   parityErrorOnLastByte = isParityError;
442                 }
443             */
444                 com1.Open();
445                 com2.Open();
446                 PerformWriteRead(com1, com2, xmitBytes, expectedBytes);
447             }
448         }
449 
VerifyWriteParity(int parity, int dataBits, int numBytesToSend)450         private void VerifyWriteParity(int parity, int dataBits, int numBytesToSend)
451         {
452             byte[] xmitBytes = new byte[numBytesToSend];
453             byte[] expectedBytes = new byte[numBytesToSend];
454             Random rndGen = new Random();
455             using (SerialPort com1 = new SerialPort(TCSupport.LocalMachineSerialInfo.FirstAvailablePortName))
456             using (SerialPort com2 = new SerialPort(TCSupport.LocalMachineSerialInfo.SecondAvailablePortName))
457             {
458                 //Generate some random bytes to read/write for this Parity setting
459                 for (int i = 0; i < xmitBytes.Length; i++)
460                 {
461                     xmitBytes[i] = (byte)rndGen.Next(0, 256);
462                     expectedBytes[i] = SetParityBit((byte)(xmitBytes[i]), dataBits, (Parity)parity);
463                 }
464 
465                 if (8 > dataBits)
466                     com2.DataBits = dataBits + 1;
467                 else
468                     com2.Parity = (Parity)parity;
469 
470                 com1.Parity = (Parity)parity;
471                 com1.DataBits = dataBits;
472                 com1.Open();
473                 com2.Open();
474 
475                 PerformWriteRead(com1, com2, xmitBytes, expectedBytes);
476             }
477         }
478 
479 
PerformWriteRead(SerialPort com1, SerialPort com2, byte[] xmitBytes, byte[] expectedBytes)480         private void PerformWriteRead(SerialPort com1, SerialPort com2, byte[] xmitBytes, byte[] expectedBytes)
481         {
482             byte[] rcvBytes = new byte[expectedBytes.Length * 4];
483             Stopwatch sw = new Stopwatch();
484             double expectedTime, actualTime, percentageDifference;
485             int numParityBits = (Parity)com1.Parity == Parity.None ? 0 : 1;
486             double numStopBits = GetNumberOfStopBits(com1);
487             int length = xmitBytes.Length;
488             int rcvLength;
489 
490             // TODO: Consider removing all of the code to check the time it takes to transfer the bytes.
491             // This was likely just a copy and paste from another test case
492             actualTime = 0;
493             Thread.CurrentThread.Priority = ThreadPriority.Highest;
494             for (int i = 0; i < NUM_TRYS; i++)
495             {
496                 com2.DiscardInBuffer();
497 
498                 IAsyncResult beginWriteResult = com1.BaseStream.BeginWrite(xmitBytes, 0, length, null, null);
499 
500                 while (0 == com2.BytesToRead) ;
501 
502                 sw.Start();
503 
504                 // Wait for all of the bytes to reach the input buffer of com2
505                 TCSupport.WaitForReadBufferToLoad(com2, length);
506 
507                 sw.Stop();
508                 actualTime += sw.ElapsedMilliseconds;
509                 beginWriteResult.AsyncWaitHandle.WaitOne();
510                 sw.Reset();
511             }
512 
513             Thread.CurrentThread.Priority = ThreadPriority.Normal;
514             actualTime /= NUM_TRYS;
515             expectedTime = ((xmitBytes.Length * (1 + numStopBits + com1.DataBits + numParityBits)) / com1.BaudRate) * 1000;
516             percentageDifference = Math.Abs((expectedTime - actualTime) / expectedTime);
517 
518             //If the percentageDifference between the expected time and the actual time is to high
519             //then the expected baud rate must not have been used and we should report an error
520             if (MAX_ACCEPTABEL_PERCENTAGE_DIFFERENCE < percentageDifference)
521             {
522                 Fail("ERROR!!! Parity not used Expected time:{0}, actual time:{1} percentageDifference:{2}", expectedTime, actualTime, percentageDifference);
523             }
524 
525             rcvLength = com2.Read(rcvBytes, 0, rcvBytes.Length);
526             if (0 != com2.BytesToRead)
527             {
528                 Fail("ERROR!!! BytesToRead={0} expected 0", com2.BytesToRead);
529             }
530 
531             //Verify that the bytes we sent were the same ones we received
532             int expectedIndex = 0, actualIndex = 0;
533 
534             for (; expectedIndex < expectedBytes.Length && actualIndex < rcvBytes.Length; ++expectedIndex, ++actualIndex)
535             {
536                 if (expectedBytes[expectedIndex] != rcvBytes[actualIndex])
537                 {
538                     if (actualIndex != rcvBytes.Length - 1 && expectedBytes[expectedIndex] == rcvBytes[actualIndex + 1])
539                     {
540                         //Sometimes if there is a parity error an extra byte gets added to the input stream so
541                         //look ahead at the next byte
542                         actualIndex++;
543                     }
544                     else
545                     {
546                         Debug.WriteLine("Bytes Sent:");
547                         TCSupport.PrintBytes(xmitBytes);
548 
549                         Debug.WriteLine("Bytes Recieved:");
550                         TCSupport.PrintBytes(rcvBytes);
551 
552                         Debug.WriteLine("Expected Bytes:");
553                         TCSupport.PrintBytes(expectedBytes);
554 
555                         Fail(
556                             "ERROR: Expected to read {0,2:X} at {1,3} actually read {2,2:X} sent {3,2:X}",
557                             expectedBytes[expectedIndex],
558                             expectedIndex,
559                             rcvBytes[actualIndex],
560                             xmitBytes[expectedIndex]);
561                     }
562                 }
563             }
564 
565             if (expectedIndex < expectedBytes.Length)
566             {
567                 Fail("ERRROR: Did not enumerate all of the expected bytes index={0} length={1}", expectedIndex, expectedBytes.Length);
568             }
569         }
570 
GetNumberOfStopBits(SerialPort com)571         private double GetNumberOfStopBits(SerialPort com)
572         {
573             double stopBits = -1;
574 
575             switch (com.StopBits)
576             {
577                 case StopBits.One:
578                     stopBits = 1.0;
579                     break;
580 
581                 case StopBits.OnePointFive:
582                     stopBits = 1.5;
583                     break;
584 
585                 case StopBits.Two:
586                     stopBits = 2.0;
587                     break;
588 
589                 default:
590                     throw new ArgumentOutOfRangeException();
591             }
592             return stopBits;
593         }
594 
595 
SetParityBit(byte parityByte, int dataBitSize, Parity parity)596         private byte SetParityBit(byte parityByte, int dataBitSize, Parity parity)
597         {
598             byte result;
599 
600             if (8 == dataBitSize)
601             {
602                 return parityByte;
603             }
604 
605             switch (parity)
606             {
607                 case Parity.Even:
608                     if (VerifyEvenParity(parityByte, dataBitSize))
609                         result = (byte)(parityByte & (0xFF >> 8 - dataBitSize));
610                     else
611                         result = (byte)(parityByte | (0x80 >> 8 - (dataBitSize + 1)));
612 
613                     break;
614 
615                 case Parity.Odd:
616                     if (VerifyOddParity(parityByte, dataBitSize))
617                         result = (byte)(parityByte & (0xFF >> 8 - dataBitSize));
618                     else
619                         result = (byte)(parityByte | (0x80 >> 8 - (dataBitSize + 1)));
620 
621                     break;
622 
623                 case Parity.Mark:
624                     result = (byte)(parityByte | (0x80 >> 8 - (dataBitSize + 1)));
625                     break;
626 
627                 case Parity.Space:
628                     result = (byte)(parityByte & (0xFF >> 8 - dataBitSize));
629                     break;
630 
631                 default:
632                     result = 0;
633                     break;
634             }
635             if (7 > dataBitSize)
636                 result &= (byte)(0xFF >> 8 - (dataBitSize + 1));
637 
638             return result;
639         }
640 
641 
VerifyParityByte(byte parityByte, int parityWordSize, Parity parity)642         private bool VerifyParityByte(byte parityByte, int parityWordSize, Parity parity)
643         {
644             switch (parity)
645             {
646                 case Parity.Even:
647                     return VerifyEvenParity(parityByte, parityWordSize);
648 
649                 case Parity.Odd:
650                     return VerifyOddParity(parityByte, parityWordSize);
651 
652                 case Parity.Mark:
653                     return VerifyMarkParity(parityByte, parityWordSize);
654 
655                 case Parity.Space:
656                     return VerifySpaceParity(parityByte, parityWordSize);
657 
658                 default:
659                     return false;
660             }
661         }
662 
VerifyEvenParity(byte parityByte, int parityWordSize)663         private bool VerifyEvenParity(byte parityByte, int parityWordSize)
664         {
665             return (0 == CalcNumberOfTrueBits(parityByte, parityWordSize) % 2);
666         }
667 
VerifyOddParity(byte parityByte, int parityWordSize)668         private bool VerifyOddParity(byte parityByte, int parityWordSize)
669         {
670             return (1 == CalcNumberOfTrueBits(parityByte, parityWordSize) % 2);
671         }
672 
VerifyMarkParity(byte parityByte, int parityWordSize)673         private bool VerifyMarkParity(byte parityByte, int parityWordSize)
674         {
675             byte parityMask = 0x80;
676 
677             parityByte <<= 8 - parityWordSize;
678             return (0 != (parityByte & parityMask));
679         }
680 
VerifySpaceParity(byte parityByte, int parityWordSize)681         private bool VerifySpaceParity(byte parityByte, int parityWordSize)
682         {
683             byte parityMask = 0x80;
684 
685             parityByte <<= 8 - parityWordSize;
686             return (0 == (parityByte & parityMask));
687         }
688 
CalcNumberOfTrueBits(byte parityByte, int parityWordSize)689         private int CalcNumberOfTrueBits(byte parityByte, int parityWordSize)
690         {
691             byte parityMask = 0x80;
692             int numTrueBits = 0;
693 
694             //Debug.WriteLine("parityByte={0}", System.Convert.ToString(parityByte, 16));
695             parityByte <<= 8 - parityWordSize;
696 
697             for (int i = 0; i < parityWordSize; i++)
698             {
699                 if (0 != (parityByte & parityMask))
700                     numTrueBits++;
701 
702                 parityByte <<= 1;
703             }
704 
705             //Debug.WriteLine("Number of true bits: {0}", numTrueBits);
706             return numTrueBits;
707         }
708         #endregion
709     }
710 }
711