/// <summary>
      /// Reads the data.
      /// </summary>
      /// <param name="cancellationToken">The cancellation token.</param>
      //[DebuggerStepThrough]
      private void ReadData(CancellationToken cancellationToken)
      {
         using (this.Sp = new SerialPort(portName, 9600, Parity.None, 8, StopBits.One))
         {
            try
            {
               this.Sp.Open();
            }
            catch (Exception ex)
            {
               this.OnScannerError(new MatrixCodeScannerErrorEventArgs(string.Format("Fehler beim Zugriff auf den Scanner Port {0} - '{1}'", portName, ex.Message), ex.StackTrace));
               return;
            }

            var readResultBuffer = new List<byte>();
            byte[] readBuffer;

            var sw = new Stopwatch();
            while (cancellationToken.IsCancellationRequested == false)
            {
               readResultBuffer.Clear();
               readBuffer = new byte[4096];

               Thread.Sleep(100);

               if (this.Sp.BytesToRead <= 0)
               {
                  continue;
               }

               var isDataComplete = false;
               var lineCount = 0;
               sw.Restart();
               
               // reading loop when bytes are available
               while (sw.Elapsed.TotalSeconds < 40)
               {
                  Thread.Sleep(400);
                  if (isDataComplete)
                  {
                     break;
                  }

                  if (this.Sp.BytesToRead > 0 == false)
                  {
                     break;
                  }

                  var bytesRead = this.Sp.Read(readBuffer, 0, readBuffer.Count());

                  for (int i = 0; i < bytesRead; i++)
                  {
                     readResultBuffer.Add(readBuffer[i]);
                     if (i > 0 == false)
                     {
                        continue;
                     }

                     if (readBuffer[i - 1] == 10 && readBuffer[i] == 13)
                     {
                        lineCount++;
                        if (lineCount == 4)
                        {
                           isDataComplete = true;
                        }
                     }
                  }

                  if (isDataComplete)
                  {
                     var scannedBlock = Encoding.UTF8.GetString(readResultBuffer.ToArray());
                     var readLines = scannedBlock.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);

                     if (readLines.Count() != 5)
                     {
                        break;
                     }

                     var targetLines = new List<string>();
                     for (int i = 0; i < readLines.Count(); i++)
                     {
                        if (readLines[i].Length > 0)
                        {
                           targetLines.Add(readLines[i]);
                        }
                     }

                     var eventArgs = new MatrixCodeScannerEventArgs(
                        targetLines[0], targetLines[1], targetLines[2], targetLines[3], targetLines[4]);
                     this.OnScannerDataReceived(eventArgs);

                     break;
                  }
               }
            }

            // release delegate.
            this.ScannerDataReceived = null;
         }
      }
        /// <summary>
        /// Called when [scanner data received].
        /// </summary>
        /// <param name="sndr">The SNDR.</param>
        /// <param name="scnevnt">The <see cref="ConfigurationClient.MatrixCodeScannerEventArgs"/> instance containing the event data.</param>
        private void OnScannerDataReceived(object sndr, MatrixCodeScannerEventArgs scnevnt)
        {
            this.InvokeEx(f => f.txtScanPublicKeyReal.Text = scnevnt.PublicKey);
            this.InvokeEx(f => f.txtScanSerialNoReal.Text = scnevnt.SerialNo);
            this.InvokeEx(f => f.txtScanServerIdReal.Text = scnevnt.ServerId);
            this.InvokeEx(f => f.txtScanEigentumsnrReal.Text = scnevnt.Eigentumsnummer);
            this.InvokeEx(f => f.txtScanTypCodeReal.Text = scnevnt.TypCode);

            if (this.activePort == null)
            {
                return;
            }

            this.activePort.ScanStatus = PortScanStatus.ScanFailed;
            var matrixCodeParams = this.activePort.ParameterList.Where(p => p.IsPartOfMatrixCode);
            Logger.Debug("Number of matrix code params: {0}, mapping scanned values...", matrixCodeParams.Count());
            foreach (var matrixCodeParam in matrixCodeParams)
            {
                switch (matrixCodeParam.Id)
                {
                    case ParameterId.ServerId:
                        matrixCodeParam.ScannedValue = scnevnt.ServerId;
                        break;
                    case ParameterId.PublicKey:
                        matrixCodeParam.ScannedValue = scnevnt.PublicKey;
                        break;
                    case ParameterId.Typ:
                        matrixCodeParam.ScannedValue = scnevnt.TypCode;
                        break;
                    case ParameterId.ManufacturerSerialNumber:
                        matrixCodeParam.ScannedValue = scnevnt.SerialNo;
                        break;
                    case ParameterId.Eigentumsnummer:
                        matrixCodeParam.ScannedValue = scnevnt.Eigentumsnummer;
                        break;
                    default:
                        MessageBox.Show(
                           string.Format(
                              "Illegal port configuration, unexpected matrixcodeparam id:'{0}'.", matrixCodeParam.Id));
                        break;
                }
            }


            if (matrixCodeParams.All(p => p.IsScannedValid))
            {
                Logger.Info("allValid:true -> matrixCodeParams.All(p => p.IsScannedValid)");
                this.activePort.ScanStatus = PortScanStatus.ScanOk;
            }

            // set for some seconds the background color of the real scan values group box depending on the scan result
            var t = Task.Factory.StartNew(
               () =>
               {
                   // switch back color of group box for some seconds to read or green
                   Color backClr;
                   backClr = this.activePort.ScanStatus == PortScanStatus.ScanOk ? Color.Green : Color.Red;
                   this.InvokeEx(f => f.groupBoxScanReal.BackColor = backClr);
                   Thread.Sleep(1500);
                   this.InvokeEx(f => f.groupBoxScanReal.BackColor = Color.Transparent);

                   if (this.activePort.ScanStatus == PortScanStatus.ScanOk)
                   {
                       // move selected node to next one
                       var oldIndex = this.tvMatrixCodePorts.SelectedNode.Index;
                       Logger.Debug("TreeIndexOld: {0}.", oldIndex);

                       var nextPort =
                          this.portList.FirstOrDefault(
                             p => p.IsActive && p.TestStationId == this.activePort.TestStationId + 1);

                       if (nextPort != null)
                       {
                           var nodeToSelect = this.GetTreeNodeForPort(this.tvMatrixCodePorts, nextPort);
                           this.InvokeEx(f => f.tvMatrixCodePorts.SelectedNode = nodeToSelect);
                           this.InvokeEx(f => f.lblActiveScanPort.Text = string.Format("{0}", this.activePort.TestStationId));
                       }

                       //if (this.tvMatrixCodePorts.Nodes.First().Nodes.Count > oldIndex + 1)
                       //{
                       //   Logger.Debug("Moving tree index forward by 1.");
                       //   this.InvokeEx(f => f.tvMatrixCodePorts.SelectedNode = this.tvMatrixCodePorts.Nodes.First().Nodes[oldIndex + 1]);
                       //   this.InvokeEx(f => f.lblActiveScanPort.Text = string.Format("{0}", this.activePort.TestStationId));
                       //}
                   }
               });
        }
 /// <summary>
 /// Raises the <see cref="E:ScannerDataReceived"/> event.
 /// </summary>
 /// <param name="eventArgs">The <see cref="ConfigurationClient.MatrixCodeScannerEventArgs"/> instance containing the event data.</param>
 protected virtual void OnScannerDataReceived(MatrixCodeScannerEventArgs eventArgs)
 {
    // copy for thread safety
    var eventCopy = this.ScannerDataReceived;
    if (eventCopy != null)
    {
       // forward event delegate
       eventCopy(this, eventArgs);
    }
 }