context: //
  // --------------------------------------------------------------------------
  //  Gurux Ltd
  //
  //
  //
  //
  // Version:         $Revision: 9442 $,
  //                  $Date: 2017-05-23 15:21:03 +0300 (ti, 23 touko 2017) $
  //                  $Author: gurux01 $
  //
  // Copyright (c) Gurux Ltd
  //
  //---------------------------------------------------------------------------
  //
  //  DESCRIPTION
  //
  // This file is a part of Gurux Device Framework.
  //
  // Gurux Device Framework is Open Source software; you can redistribute it
  // and/or modify it under the terms of the GNU General Public License
  // as published by the Free Software Foundation; version 2 of the License.
  // Gurux Device Framework is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  // See the GNU General Public License for more details.
  //
  // More information of Gurux DLMS/COSEM Director: https://www.gurux.org/GXDLMSDirector
  //
  // This code is licensed under the GNU General Public License v2.
  // Full text may be retrieved at http://www.gnu.org/licenses/gpl-2.0.txt
  //---------------------------------------------------------------------------
  
  using System;
  using System.Windows.Forms;
  using Gurux.DLMS;
  using Gurux.Serial;
  using Gurux.Common;
  using Gurux.Net;
  using GXDLMSDirector.Properties;
  using System.Collections.Generic;
  using System.Diagnostics;
  using Gurux.DLMS.Enums;
  using System.Collections;
  using Gurux.DLMS.Plc;
  using Gurux.DLMS.Plc.Enums;
  
  namespace GXDLMSDirector
  {
      public partial class GXPlcDiscover : Form
      {
          MainForm _parent;
          IGXMedia media;
          GXAsyncWork ScanWork;
  
          public GXPlcDiscover(MainForm parent)
          {
              InitializeComponent();
              MetersView_SelectedIndexChanged(null, null);
              _parent = parent;
              try
              {
                  if (Settings.Default.PlcInterface == (int)InterfaceType.PlcHdlc)
                  {
                      SFskMnu.Checked = true;
                  }
                  else
                  {
                      LlcMnu.Checked = true;
                  }
                  if (Settings.Default.PlcMedia == "GXSerial" && GXSerial.GetPortNames().Length != 0)
                  {
                      OnMediaTypeChanged(SerialMnu, null);
                  }
                  else
                  {
                      OnMediaTypeChanged(NetworkMnu, null);
                  }
              }
              catch (Exception ex)
              {
                  MessageBox.Show(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                  Close();
              }
          }
  
          private void OnReceived(object sender, ReceiveEventArgs e)
          {
              if (InvokeRequired)
              {
                  BeginInvoke(new ReceivedEventHandler(OnReceived), sender, e);
              }
              else
              {
                  try
                  {
                      TraceView.AppendText(GXCommon.ToHex((byte[])e.Data));
                  }
                  catch (Exception ex)
                  {
                      TraceView.AppendText(ex.Message);
                  }
              }
          }
  
          void OnAsyncStateChange(object sender, GXAsyncWork work, object[] parameters, AsyncState state, string text)
          {
              if (InvokeRequired)
              {
                  BeginInvoke(new AsyncStateChangeEventHandler(OnAsyncStateChange), sender, work, parameters, state, text);
              }
              else
              {
                  if (state != AsyncState.Start)
                  {
                      RegisterMnu.Enabled = true;
                      media.Close();
                      BeginInvoke(new ResetProgressEventHandler(OnResetProgress), 0, true);
                  }
                  else
                  {
                      RegisterMnu.Enabled = false;
                  }
                  MetersView_SelectedIndexChanged(null, null);
              }
          }
  
          void OnError(object sender, Exception ex)
          {
              MessageBox.Show(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
          }
  
          delegate void IncreaseProgressEventHandler();
  
          void OnIncreaseProgress()
          {
              ++ProgressBar.Value;
          }
  
          delegate void AppendMeterEventHandler(List<GXDLMSPlcMeterInfo> list);
  
          Hashtable _meters = new Hashtable();
  
  
          void OnAppendMeter(List<GXDLMSPlcMeterInfo> list)
          {
              foreach (GXDLMSPlcMeterInfo it in list)
              {
                  string str = "";
                  if (it.SourceAddress == (UInt16)PlcSourceAddress.New)
                  {
                      str = "New meter";
                  }
                  else if (it.AlarmDescriptor == 0x82)
                  {
                      str = "Registered";
                  }
                  else if (it.AlarmDescriptor != 0)
                  {
                      str = it.AlarmDescriptor.ToString();
                  }
                  ListViewItem li = (ListViewItem)_meters[GXCommon.ToHex(it.SystemTitle)];
                  string sa;
                  if (it.SourceAddress == (UInt16)PlcSourceAddress.New)
                  {
                      sa = "New (0x" + it.SourceAddress.ToString("X") + ")";
                  }
                  else if (it.SourceAddress == (UInt16)PlcSourceAddress.Initiator)
                  {
                      sa = "Initiator (0x" + it.SourceAddress.ToString("X") + ")";
                  }
                  else
                  {
                      sa = "0x" + it.SourceAddress.ToString("X");
                  }
                  if (li == null)
                  {
                      li = new ListViewItem(new string[] { GXCommon.ToHex(it.SystemTitle), str, sa});
                      li.Tag = it;
                      _meters.Add(li.Text, li);
                      MetersView.Items.Add(li);
                  }
                  else
                  {
                      li.SubItems[1].Text = str;
                      li.SubItems[2].Text = sa;
                  }
              }
          }
  
          delegate void ResetProgressEventHandler(int count, bool reset);
  
          void OnResetProgress(int count, bool reset)
          {
              ProgressBar.Maximum = count;
              if (reset)
              {
                  ProgressBar.Value = 0;
              }
          }
  
          /// <summary>
          /// Try to find client and server address from the meter.
          /// </summary>
          private void DiscoverMeters(object sender, GXAsyncWork work, object[] parameters)
          {
              GXDLMSClient cl = new GXDLMSClient(true, 16, 1, Authentication.None, null, (InterfaceType)Settings.Default.PlcInterface);
              byte[] data = cl.Plc.DiscoverRequest();
              ReceiveParameters<byte[]> p = new ReceiveParameters<byte[]>()
              {
                  AllData = false,
                  Count = 8,
                  WaitTime = 10000,
              };
              DateTime start = DateTime.Now;
              GXByteBuffer rd = new GXByteBuffer();
              lock (media.Synchronous)
              {
                  if (data != null)
                  {
                      media.Send(data, null);
                      start = DateTime.Now;
                  }
                  GXReplyData reply = new GXReplyData();
                  rd = new GXByteBuffer(p.Reply);
                  try
                  {
                      while (!work.IsCanceled)
                      {
                          p.Reply = null;
                          //If Eop is not set read one byte at time.
                          if (p.Eop == null)
                          {
                              p.Count = cl.GetFrameSize(rd);
                          }
                          if (!media.IsOpen)
                          {
                              throw new InvalidOperationException("Media is closed.");
                          }
                          if (!media.Receive(p))
                          {
                              //It's OK if there is no reply. Read again
                              continue;
                          }
                          rd.Position = 0;
                          rd.Set(p.Reply);
                          if (cl.GetData(rd, reply))
                          {
                              List<GXDLMSPlcMeterInfo> list = cl.Plc.ParseDiscover(reply.Data, (UInt16)reply.TargetAddress, (UInt16)reply.SourceAddress);
                              BeginInvoke(new AppendMeterEventHandler(OnAppendMeter), list);
                          }
                      }
                  }
                  catch (Exception)
                  {
                      //Throw original exception.
                      throw;
                  }
              }
          }
  
          private void OnMediaStateChange(object sender, MediaStateEventArgs e)
          {
              if (InvokeRequired)
              {
                  BeginInvoke(new MediaStateChangeEventHandler(OnMediaStateChange), sender, e);
              }
              else
              {
                  try
                  {
                      if (e.State == Gurux.Common.MediaState.Opening)
                      {
                          DiscoverBtn.Checked = true;
                          MediaSettingsBtn.Enabled = MediaMnu.Enabled = MediaSettingsMnu.Enabled = false;
                          TraceView.Text = "";
                          DiscoverMnu.Text = "Stop";
                          UpdateStatus("Discovering.");
                      }
                      else if (e.State == Gurux.Common.MediaState.Closed)
                      {
                          DiscoverBtn.Checked = false;
                          MediaSettingsBtn.Enabled = MediaMnu.Enabled = MediaSettingsMnu.Enabled = true;
                          DiscoverMnu.Text = "Discover";
                          UpdateStatus("Ready.");
  
gt:                         if (ScanWork != null)