Esempio n. 1
8
        static void Main(string[] args)
        {
            IGXMedia media = null;
            GXCommunicatation comm = null;
            try
            {
                TextWriter logFile = new StreamWriter(File.Open("LogFile.txt", FileMode.Create));
                ////////////////////////////////////////
                //Handle command line parameters.
                String sn, client = "", server = "", id = "", host = "", port = "", pw = "";
                bool trace = false, iec = true;
                bool hdlc = true, ln = true;
                Authentication auth = Authentication.None;
                foreach (string it in args)
                {
                    String item = it.Trim().ToLower();
                    if (string.Compare(item, "/u", true) == 0)//Update
                    {
                        //Get latest manufacturer settings from Gurux web server.
                        GXManufacturerCollection.UpdateManufactureSettings();
                    }
                    else if (item.StartsWith("/sn="))//Serial number.
                    {
                        sn = item.Replace("/sn=", "");
                    }
                    else if (string.Compare(item, "/wrapper", true) == 0)//Wrapper is used.
                    {
                        hdlc = false;
                    }
                    else if (item.StartsWith("/r="))//referencing
                    {
                        id = item.Replace("/r=", "");
                    }
                    else if (item.StartsWith("/m="))//Manufacturer
                    {
                        id = item.Replace("/m=", "");
                    }
                    else if (item.StartsWith("/client="))//Client address
                    {
                        client = item.Replace("/client=", "");
                    }
                    else if (item.StartsWith("/server="))//Server address
                    {
                        server = item.Replace("/server=", "");
                    }
                    else if (item.StartsWith("/h=")) //Host
                    {
                        host = item.Replace("/h=", "");
                    }
                    else if (item.StartsWith("/p="))// TCP/IP Port
                    {
                        media = new Gurux.Net.GXNet();
                        port = item.Replace("/p=", "");
                    }
                    else if (item.StartsWith("/sp="))//Serial Port
                    {
                        port = item.Replace("/sp=", "");
                        media = new GXSerial();
                    }
                    else if (item.StartsWith("/t"))//Are messages traced.
                    {
                        trace = true;
                    }
                    else if (item.StartsWith("/s="))//Start
                    {
                        String tmp = item.Replace("/s=", "");
                        iec = string.Compare(tmp, "dlms", true) != 0;
                    }
                    else if (item.StartsWith("/a="))//Authentication
                    {
                        auth = (Authentication)Enum.Parse(typeof(Authentication), it.Trim().Replace("/a=", ""));
                    }
                    else if (item.StartsWith("/pw="))//Password
                    {
                        pw = it.Trim().Replace("/pw=", "");
                    }
                    else
                    {
                        ShowHelp();
                        return;
                    }
                }
                if (string.IsNullOrEmpty(id) || string.IsNullOrEmpty(port) || (media is GXNet && string.IsNullOrEmpty(host)))
                {
                    ShowHelp();
                    return;
                }
                ////////////////////////////////////////
                //Initialize connection settings.
                if (media is GXSerial)
                {
                    GXSerial serial = media as GXSerial;
                    serial.PortName = port;
                    if (iec)
                    {
                        serial.BaudRate = 300;
                        serial.DataBits = 7;
                        serial.Parity = System.IO.Ports.Parity.Even;
                        serial.StopBits = System.IO.Ports.StopBits.One;
                    }
                    else
                    {
                        serial.BaudRate = 9600;
                        serial.DataBits = 8;
                        serial.Parity = System.IO.Ports.Parity.None;
                        serial.StopBits = System.IO.Ports.StopBits.One;
                    }
                }
                else if (media is GXNet)
                {
                    Gurux.Net.GXNet net = media as GXNet;
                    net.Port = Convert.ToInt32(port);
                    net.HostName = host;
                    net.Protocol = Gurux.Net.NetworkType.Tcp;
                }
                else
                {
                    throw new Exception("Unknown media type.");
                }
                ////////////////////////////////////////
                //Update manufacturer depended settings.
                GXManufacturerCollection Manufacturers = new GXManufacturerCollection();
                GXManufacturerCollection.ReadManufacturerSettings(Manufacturers);
                GXManufacturer man = Manufacturers.FindByIdentification(id);
                if (man == null)
                {
                    throw new Exception("Unknown manufacturer: " + id);
                }
                GXDLMSSecureClient dlms = new GXDLMSSecureClient();
                //Update Obis code list so we can get right descriptions to the objects.
                dlms.CustomObisCodes = man.ObisCodes;
                comm = new GXCommunicatation(dlms, media, iec, auth, pw);
                comm.Trace = trace;
                comm.InitializeConnection(man);
                GXDLMSObjectCollection objects = null;
                string path = host.Replace('.', '_') + "_" + port.ToString() + ".xml";

                List<Type> extraTypes = new List<Type>(Gurux.DLMS.GXDLMSClient.GetObjectTypes());
                extraTypes.Add(typeof(GXDLMSAttributeSettings));
                extraTypes.Add(typeof(GXDLMSAttribute));
                XmlSerializer x = new XmlSerializer(typeof(GXDLMSObjectCollection), extraTypes.ToArray());
                //You can save association view, but make sure that it is not change.
                //Save Association view to the cache so it is not needed to retrieve every time.
                /*
                if (File.Exists(path))
                {
                    try
                    {
                        using (Stream stream = File.Open(path, FileMode.Open))
                        {
                            Console.WriteLine("Get available objects from the cache.");
                            objects = x.Deserialize(stream) as GXDLMSObjectCollection;
                            stream.Close();
                        }
                    }
                    catch (Exception ex)
                    {
                        if (File.Exists(path))
                        {
                            File.Delete(path);
                        }
                        throw ex;
                    }
                }
                else
                 */
                {
                    Console.WriteLine("Get available objects from the device.");
                    objects = comm.GetAssociationView();
                    GXDLMSObjectCollection objs = objects.GetObjects(new ObjectType[] { ObjectType.Register, ObjectType.ExtendedRegister, ObjectType.DemandRegister });
                    Console.WriteLine("Read scalers and units from the device.");
                    List<KeyValuePair<GXDLMSObject, int>> list = new List<KeyValuePair<GXDLMSObject, int>>();
                    try
                    {
                        foreach (GXDLMSObject it in objs)
                        {
                            if (it is GXDLMSRegister)
                            {
                                list.Add(new KeyValuePair<GXDLMSObject, int>(it, 3));
                            }
                            if (it is GXDLMSDemandRegister)
                            {
                                list.Add(new KeyValuePair<GXDLMSObject, int>(it, 4));
                            }
                        }
                        comm.ReadList(list);
                    }
                    catch
                    {
                        //If this fails meter is not supporting reading read by list method.
                        //Read values one by one.
                        foreach (GXDLMSObject it in objs)
                        {
                            try
                            {
                                if (it is GXDLMSRegister)
                                {
                                    Console.WriteLine(it.Name);
                                    comm.Read(it, 3);
                                }
                                if (it is GXDLMSDemandRegister)
                                {
                                    Console.WriteLine(it.Name);
                                    comm.Read(it, 4);
                                }
                            }
                            catch
                            {
                                //Actaric SL7000 can return error here. Continue reading.
                            }
                        }
                    }
                    //Read Profile Generic columns first.
                    foreach (GXDLMSObject it in objects.GetObjects(ObjectType.ProfileGeneric))
                    {
                        try
                        {
                            Console.WriteLine(it.Name);
                            comm.Read(it, 3);
                            GXDLMSObject[] cols = (it as GXDLMSProfileGeneric).GetCaptureObject();
                            TraceLine(logFile, "Profile Generic " + it.Name + " Columns:");
                            StringBuilder sb = new StringBuilder();
                            bool First = true;
                            foreach (GXDLMSObject col in cols)
                            {
                                if (!First)
                                {
                                    sb.Append(" | ");
                                }
                                First = false;
                                sb.Append(col.Name);
                                sb.Append(" ");
                                sb.Append(col.Description);
                            }
                            TraceLine(logFile, sb.ToString());
                        }
                        catch (Exception ex)
                        {
                            TraceLine(logFile, "Err! Failed to read columns:" + ex.Message);
                            //Continue reading.
                        }
                    }
                    try
                    {
                        using (Stream stream = File.Open(path, FileMode.Create))
                        {
                            TextWriter writer = new StreamWriter(stream);
                            x.Serialize(writer, objects);
                            writer.Close();
                            stream.Close();
                        }
                    }
                    catch (Exception ex)
                    {
                        if (File.Exists(path))
                        {
                            File.Delete(path);
                        }
                        throw ex;
                    }
                    Console.WriteLine("--- Available objects ---");
                    foreach (GXDLMSObject it in objects)
                    {
                        Console.WriteLine(it.Name + " " + it.Description);
                    }
                }
                foreach (GXDLMSObject it in objects)
                {
                    // Profile generics are read later because they are special cases.
                    // (There might be so lots of data and we so not want waste time to read all the data.)
                    if (it is GXDLMSProfileGeneric)
                    {
                        continue;
                    }
                    if (!(it is IGXDLMSBase))
                    {
                        //If interface is not implemented.
                        //Example manufacturer spesific interface.
                        Console.WriteLine("Unknown Interface: " + it.ObjectType.ToString());
                        continue;
                    }
                    TraceLine(logFile, "-------- Reading " + it.GetType().Name + " " + it.Name + " " + it.Description);
                    foreach (int pos in (it as IGXDLMSBase).GetAttributeIndexToRead())
                    {
                        try
                        {
                            object val = comm.Read(it, pos);
                            //If data is array.
                            if (val is byte[])
                            {
                                val = GXCommon.ToHex((byte[])val, true);
                            }
                            else if (val is Array)
                            {
                                string str = "";
                                for (int pos2 = 0; pos2 != (val as Array).Length; ++pos2)
                                {
                                    if (str != "")
                                    {
                                        str += ", ";
                                    }
                                    if ((val as Array).GetValue(pos2) is byte[])
                                    {
                                        str += GXCommon.ToHex((byte[])(val as Array).GetValue(pos2), true);
                                    }
                                    else
                                    {
                                        str += (val as Array).GetValue(pos2).ToString();
                                    }
                                }
                                val = str;
                            }
                            else if (val is System.Collections.IList)
                            {
                                string str = "[";
                                bool empty = true;
                                foreach (object it2 in val as System.Collections.IList)
                                {
                                    if (!empty)
                                    {
                                        str += ", ";
                                    }
                                    empty = false;
                                    if (it2 is byte[])
                                    {
                                        str += GXCommon.ToHex((byte[])it2, true);
                                    }
                                    else
                                    {
                                        str += it2.ToString();
                                    }
                                }
                                str += "]";
                                val = str;
                            }
                            TraceLine(logFile, "Index: " + pos + " Value: " + val);
                        }
                        catch (Exception ex)
                        {
                            TraceLine(logFile, "Error! Index: " + pos + " " + ex.Message);
                        }
                    }
                }
                //Find profile generics and read them.
                foreach (GXDLMSObject it in objects.GetObjects(ObjectType.ProfileGeneric))
                {
                    TraceLine(logFile, "-------- Reading " + it.GetType().Name + " " + it.Name + " " + it.Description);
                    long entriesInUse = Convert.ToInt64(comm.Read(it, 7));
                    long entries = Convert.ToInt64(comm.Read(it, 8));
                    TraceLine(logFile, "Entries: " + entriesInUse + "/" + entries);
                    //If there are no columns or rows.
                    if (entriesInUse == 0 || (it as GXDLMSProfileGeneric).CaptureObjects.Count == 0)
                    {
                        continue;
                    }
                    try
                    {
                        //Read first row from Profile Generic.
                        object[] rows = comm.ReadRowsByEntry(it as GXDLMSProfileGeneric, 1, 1);
                        StringBuilder sb = new StringBuilder();
                        foreach (object[] row in rows)
                        {
                            foreach (object cell in row)
                            {
                                if (cell is byte[])
                                {
                                    sb.Append(GXCommon.ToHex((byte[])cell, true));
                                }
                                else
                                {
                                    sb.Append(Convert.ToString(cell));
                                }
                                sb.Append(" | ");
                            }
                            sb.Append("\r\n");
                        }
                        Trace(logFile, sb.ToString());
                    }
                    catch (Exception ex)
                    {
                        TraceLine(logFile, "Error! Failed to read first row: " + ex.Message);
                        //Continue reading.
                    }
                    try
                    {
                        //Read last day from Profile Generic.
                        object[] rows = comm.ReadRowsByRange(it as GXDLMSProfileGeneric, DateTime.Now.Date, DateTime.MaxValue);
                        StringBuilder sb = new StringBuilder();
                        foreach (object[] row in rows)
                        {
                            foreach (object cell in row)
                            {
                                if (cell is byte[])
                                {
                                    sb.Append(GXCommon.ToHex((byte[])cell, true));
                                }
                                else
                                {
                                    sb.Append(Convert.ToString(cell));
                                }
                                sb.Append(" | ");
                            }
                            sb.Append("\r\n");
                        }
                        Trace(logFile, sb.ToString());
                    }
                    catch (Exception ex)
                    {
                        TraceLine(logFile, "Error! Failed to read last day: " + ex.Message);
                        //Continue reading.
                    }
                }
                logFile.Flush();
                logFile.Close();
            }
            catch (Exception ex)
            {
                if (comm != null)
                {
                    comm.Close();
                }
                Console.WriteLine(ex.Message);
                if (!System.Diagnostics.Debugger.IsAttached)
                {
                    Console.ReadKey();
                }
            }
            finally
            {
                if (comm != null)
                {
                    comm.Close();
                }
                if (System.Diagnostics.Debugger.IsAttached)
                {
                    Console.WriteLine("Ended. Press any key to continue.");
                    Console.ReadKey();
                }
            }
        }
        public DevicePropertiesForm(GXManufacturerCollection manufacturers, GXDLMSDevice dev)
        {
            try
            {
                InitializeComponent();
                NetProtocolCB.Items.AddRange(new object[] { NetworkType.Tcp, NetworkType.Udp });
                this.ServerAddressTypeCB.SelectedIndexChanged += new System.EventHandler(this.ServerAddressTypeCB_SelectedIndexChanged);
                NetworkSettingsGB.Width = this.Width - NetworkSettingsGB.Left;
                SerialSettingsGB.Bounds = TerminalSettingsGB.Bounds = NetworkSettingsGB.Bounds;
                ServerAddressTypeCB.DrawMode = AuthenticationCB.DrawMode = DrawMode.OwnerDrawFixed;
                Manufacturers = manufacturers;
                //OK button is not enabled if there are no manufacturers.
                if (Manufacturers.Count == 0)
                {
                    OKBtn.Enabled = false;
                }
                //Show supported services tab only when they are read.
                if (dev == null || dev.Comm.client.SNSettings == null && dev.Comm.client.LNSettings == null)
                {
                    DeviceTab.TabPages.Remove(SupportedServicesTab);
                }
                else
                {
                    object settings = null;
                    if (dev.Comm.client.UseLogicalNameReferencing)
                    {
                        settings = dev.Comm.client.LNSettings;
                    }
                    else
                    {
                        settings = dev.Comm.client.SNSettings;
                    }
                    if (settings != null)
                    {
                        SupportedServicesGrid.SelectedObject = settings;
                        foreach (PropertyDescriptor it in TypeDescriptor.GetProperties(settings))
                        {
                            ReadOnlyAttribute att = (ReadOnlyAttribute)it.Attributes[typeof(ReadOnlyAttribute)];
                            if (att != null)
                            {
                                FieldInfo[] f = att.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
                                f[0].SetValue(att, true);
                            }
                        }
                    }
                }
                Device = dev;
                StartProtocolCB.Items.Add(StartProtocolType.IEC);
                StartProtocolCB.Items.Add(StartProtocolType.DLMS);
                int pos = 0;
                foreach (GXManufacturer it in Manufacturers)
                {
                    int index = this.ManufacturerCB.Items.Add(it);
                    if (it.Name == GXDLMSDirector.Properties.Settings.Default.SelectedManufacturer)
                    {
                        pos = index;
                    }
                }
                if (Device == null)
                {
                    Device = new GXDLMSDevice(null);
                    //Select first manufacturer.
                    if (Manufacturers.Count != 0)
                    {
                        ManufacturerCB.SelectedIndex = pos;
                    }
                }
                else
                {
                    foreach (GXManufacturer it in this.ManufacturerCB.Items)
                    {
                        if (string.Compare(it.Identification, Device.Manufacturer, true) == 0)
                        {
                            this.ManufacturerCB.SelectedItem = it;
                            break;
                        }
                    }
                    this.VerboseModeCB.Checked = dev.Verbose;
                    this.NameTB.Text = dev.Name;
                    SelectedMedia = dev.Media;
                    UseRemoteSerialCB.Checked = Device.UseRemoteSerial;
                    StartProtocolCB.SelectedItem = Device.StartProtocol;
                    PhysicalServerAddressTB.Value = Convert.ToDecimal(Device.PhysicalAddress);
                    LogicalServerAddressTB.Value = Convert.ToDecimal(Device.LogicalAddress);
                    this.ClientAddTB.Value = Convert.ToDecimal(Convert.ToUInt32(Device.ClientAddress));
                    WaitTimeTB.Value = Device.WaitTime;
                }

                ManufacturerCB.DrawMode = MediasCB.DrawMode = DrawMode.OwnerDrawFixed;
                Gurux.Net.GXNet net = new Gurux.Net.GXNet();
                //Initialize network settings.
                if (SelectedMedia is GXNet)
                {
                    this.MediasCB.Items.Add(SelectedMedia);
                    net.Protocol = Gurux.Net.NetworkType.Tcp;
                    this.HostNameTB.Text = ((GXNet)SelectedMedia).HostName;
                    this.PortTB.Text = ((GXNet)SelectedMedia).Port.ToString();
                    NetProtocolCB.SelectedItem = ((GXNet)SelectedMedia).Protocol;
                }
                else
                {
                    NetProtocolCB.SelectedItem = net.Protocol = Gurux.Net.NetworkType.Tcp;
                    this.MediasCB.Items.Add(net);
                }

                //Set maximum baud rate.
                GXSerial serial = new GXSerial();
                foreach (int it in serial.GetAvailableBaudRates(""))
                {
                    if (it != 0)
                    {
                        MaximumBaudRateCB.Items.Add(it);
                    }
                }
                if (Device.MaximumBaudRate == 0)
                {
                    UseMaximumBaudRateCB.Checked = false;
                    UseMaximumBaudRateCB_CheckedChanged(null, null);
                }
                else
                {
                    UseMaximumBaudRateCB.Checked = true;
                    this.MaximumBaudRateCB.SelectedItem = Device.MaximumBaudRate;
                }

                if (SelectedMedia is GXSerial)
                {
                    this.MediasCB.Items.Add(SelectedMedia);
                    string[] ports = GXSerial.GetPortNames();
                    this.SerialPortCB.Items.AddRange(ports);
                    if (ports.Length != 0)
                    {
                        this.SerialPortCB.SelectedItem = ((GXSerial)SelectedMedia).PortName;
                    }
                }
                else
                {
                    //Initialize serial settings.
                    string[] ports = GXSerial.GetPortNames();
                    this.SerialPortCB.Items.AddRange(ports);
                    if (ports.Length != 0)
                    {
                        serial.PortName = ports[0];
                    }
                    if (((GXManufacturer)ManufacturerCB.SelectedItem).StartProtocol == StartProtocolType.DLMS)
                    {
                        serial.BaudRate = 9600;
                        serial.DataBits = 8;
                        serial.Parity = Parity.None;
                        serial.StopBits = StopBits.One;
                    }
                    else
                    {
                        serial.BaudRate = 300;
                        serial.DataBits = 7;
                        serial.Parity = Parity.Even;
                        serial.StopBits = StopBits.One;
                    }
                    this.MediasCB.Items.Add(serial);
                }
                if (SelectedMedia is Gurux.Terminal.GXTerminal)
                {
                    this.MediasCB.Items.Add(SelectedMedia);
                    string[] ports = GXTerminal.GetPortNames();
                    this.TerminalPortCB.Items.AddRange(ports);
                    if (ports.Length != 0)
                    {
                        this.TerminalPortCB.SelectedItem = ((Gurux.Terminal.GXTerminal)SelectedMedia).PortName;
                    }
                    this.TerminalPhoneNumberTB.Text = ((Gurux.Terminal.GXTerminal)SelectedMedia).PhoneNumber;
                }
                else
                {
                    //Initialize terminal settings.
                    Gurux.Terminal.GXTerminal termial = new Gurux.Terminal.GXTerminal();
                    string[] ports = GXTerminal.GetPortNames();
                    this.TerminalPortCB.Items.AddRange(ports);
                    if (ports.Length != 0)
                    {
                        termial.PortName = ports[0];
                    }
                    termial.BaudRate = 9600;
                    termial.DataBits = 8;
                    termial.Parity = Parity.None;
                    termial.StopBits = StopBits.One;
                    this.TerminalPhoneNumberTB.Text = termial.PhoneNumber;
                    //termial.InitializeCommands = "AT+CBST=71,0,1\r\n";
                    this.MediasCB.Items.Add(termial);
                }
                //Select first media if medis is not selected.
                if (SelectedMedia == null)
                {
                    SelectedMedia = (Gurux.Common.IGXMedia)this.MediasCB.Items[0];
                }
                this.MediasCB.SelectedItem = SelectedMedia;
                if (!string.IsNullOrEmpty(Device.Password))
                {
                    this.PasswordTB.Text = ASCIIEncoding.ASCII.GetString(CryptHelper.Decrypt(Device.Password, Password.Key));
                }
                if (dev != null)
                {
                    this.UseLNCB.Checked = dev.UseLogicalNameReferencing;
                }
                this.AuthenticationCB.SelectedIndexChanged += new System.EventHandler(this.AuthenticationCB_SelectedIndexChanged);
                bool bConnected = Device.Media != null && Device.Media.IsOpen;
                SerialPortCB.Enabled = AdvancedBtn.Enabled = ManufacturerCB.Enabled = MediasCB.Enabled =
                    AuthenticationCB.Enabled = UseRemoteSerialCB.Enabled = OKBtn.Enabled = !bConnected;
                HostNameTB.ReadOnly = PortTB.ReadOnly = PasswordTB.ReadOnly = WaitTimeTB.ReadOnly = PhysicalServerAddressTB.ReadOnly = NameTB.ReadOnly = bConnected;
            }
            catch (Exception Ex)
            {
                GXDLMS.Common.Error.ShowError(this, Ex);
            }
        }
Esempio n. 3
0
        static void Main(string[] args)
        {
            IGXMedia          media = null;
            GXCommunicatation comm  = null;

            try
            {
                TextWriter logFile = new StreamWriter(File.Open("LogFile.txt", FileMode.Create));
                ////////////////////////////////////////
                //Handle command line parameters.
                String         id = "", host = "", port = "", pw = "";
                bool           trace = false, iec = true;
                Authentication auth = Authentication.None;
                foreach (string it in args)
                {
                    String item = it.Trim().ToLower();
                    if (string.Compare(item, "/u", true) == 0)//Update
                    {
                        //Get latest manufacturer settings from Gurux web server.
                        GXManufacturerCollection.UpdateManufactureSettings();
                    }
                    else if (item.StartsWith("/m="))//Manufacturer
                    {
                        id = item.Replace("/m=", "");
                    }
                    else if (item.StartsWith("/h=")) //Host
                    {
                        host = item.Replace("/h=", "");
                    }
                    else if (item.StartsWith("/p="))// TCP/IP Port
                    {
                        media = new Gurux.Net.GXNet();
                        port  = item.Replace("/p=", "");
                    }
                    else if (item.StartsWith("/sp="))//Serial Port
                    {
                        port  = item.Replace("/sp=", "");
                        media = new GXSerial();
                    }
                    else if (item.StartsWith("/t"))//Are messages traced.
                    {
                        trace = true;
                    }
                    else if (item.StartsWith("/s="))//Start
                    {
                        String tmp = item.Replace("/s=", "");
                        iec = string.Compare(tmp, "dlms", true) != 0;
                    }
                    else if (item.StartsWith("/a="))//Authentication
                    {
                        auth = (Authentication)Enum.Parse(typeof(Authentication), it.Trim().Replace("/a=", ""));
                    }
                    else if (item.StartsWith("/pw="))//Password
                    {
                        pw = it.Trim().Replace("/pw=", "");
                    }
                    else
                    {
                        ShowHelp();
                        return;
                    }
                }
                if (string.IsNullOrEmpty(id) || string.IsNullOrEmpty(port) || (media is GXNet && string.IsNullOrEmpty(host)))
                {
                    ShowHelp();
                    return;
                }
                ////////////////////////////////////////
                //Initialize connection settings.
                if (media is GXSerial)
                {
                    GXSerial serial = media as GXSerial;
                    serial.PortName = port;
                    if (iec)
                    {
                        serial.BaudRate = 300;
                        serial.DataBits = 7;
                        serial.Parity   = System.IO.Ports.Parity.Even;
                        serial.StopBits = System.IO.Ports.StopBits.One;
                    }
                    else
                    {
                        serial.BaudRate = 9600;
                        serial.DataBits = 8;
                        serial.Parity   = System.IO.Ports.Parity.None;
                        serial.StopBits = System.IO.Ports.StopBits.One;
                    }
                }
                else if (media is GXNet)
                {
                    Gurux.Net.GXNet net = media as GXNet;
                    net.Port     = Convert.ToInt32(port);
                    net.HostName = host;
                    net.Protocol = Gurux.Net.NetworkType.Tcp;
                }
                else
                {
                    throw new Exception("Unknown media type.");
                }
                ////////////////////////////////////////
                //Update manufacturer depended settings.
                GXManufacturerCollection Manufacturers = new GXManufacturerCollection();
                GXManufacturerCollection.ReadManufacturerSettings(Manufacturers);
                GXManufacturer man = Manufacturers.FindByIdentification(id);
                if (man == null)
                {
                    throw new Exception("Unknown manufacturer: " + id);
                }
                GXDLMSClient dlms = new GXDLMSClient();
                //Update Obis code list so we can get right descriptions to the objects.
                dlms.CustomObisCodes = man.ObisCodes;
                comm       = new GXCommunicatation(dlms, media, iec, auth, pw);
                comm.Trace = trace;
                comm.InitializeConnection(man);
                GXDLMSObjectCollection objects = null;
                string path = host.Replace('.', '_') + "_" + port.ToString() + ".xml";

                List <Type> extraTypes = new List <Type>(Gurux.DLMS.GXDLMSClient.GetObjectTypes());
                extraTypes.Add(typeof(GXDLMSAttributeSettings));
                extraTypes.Add(typeof(GXDLMSAttribute));
                XmlSerializer x = new XmlSerializer(typeof(GXDLMSObjectCollection), extraTypes.ToArray());
                //You can save association view, but make sure that it is not change.
                //Save Association view to the cache so it is not needed to retrieve every time.

                /*
                 * if (File.Exists(path))
                 * {
                 *  try
                 *  {
                 *      using (Stream stream = File.Open(path, FileMode.Open))
                 *      {
                 *          Console.WriteLine("Get available objects from the cache.");
                 *          objects = x.Deserialize(stream) as GXDLMSObjectCollection;
                 *          stream.Close();
                 *      }
                 *  }
                 *  catch (Exception ex)
                 *  {
                 *      if (File.Exists(path))
                 *      {
                 *          File.Delete(path);
                 *      }
                 *      throw ex;
                 *  }
                 * }
                 * else
                 */
                {
                    Console.WriteLine("Get available objects from the device.");
                    objects = comm.GetAssociationView();
                    GXDLMSObjectCollection objs = objects.GetObjects(new ObjectType[] { ObjectType.Register, ObjectType.ExtendedRegister, ObjectType.DemandRegister });
                    Console.WriteLine("Read scalers and units from the device.");
                    Thread.Sleep(1000);
                    foreach (GXDLMSObject it in objs)
                    {
                        if (it is GXDLMSRegister)
                        {
                            Console.WriteLine(it.Name);
                            comm.Read(it, 3);
                        }
                        if (it is GXDLMSDemandRegister)
                        {
                            Console.WriteLine(it.Name);
                            comm.Read(it, 4);
                        }
                    }
                    Thread.Sleep(1000);
                    //Read Profile Generic columns first.
                    foreach (GXDLMSObject it in objects.GetObjects(ObjectType.ProfileGeneric))
                    {
                        try
                        {
                            Console.WriteLine(it.Name);
                            comm.Read(it, 3);
                            GXDLMSObject[] cols = (it as GXDLMSProfileGeneric).GetCaptureObject();
                            TraceLine(logFile, "Profile Generic " + it.Name + " Columns:");
                            StringBuilder sb    = new StringBuilder();
                            bool          First = true;
                            foreach (GXDLMSObject col in cols)
                            {
                                if (!First)
                                {
                                    sb.Append(" | ");
                                }
                                First = false;
                                sb.Append(col.Name);
                                sb.Append(" ");
                                sb.Append(col.Description);
                            }
                            TraceLine(logFile, sb.ToString());
                        }
                        catch (Exception ex)
                        {
                            TraceLine(logFile, "Err! Failed to read columns:" + ex.Message);
                            //Continue reading.
                        }
                    }
                    try
                    {
                        using (Stream stream = File.Open(path, FileMode.Create))
                        {
                            TextWriter writer = new StreamWriter(stream);
                            x.Serialize(writer, objects);
                            writer.Close();
                            stream.Close();
                        }
                    }
                    catch (Exception ex)
                    {
                        if (File.Exists(path))
                        {
                            File.Delete(path);
                        }
                        throw ex;
                    }
                    Console.WriteLine("--- Available objects ---");
                    foreach (GXDLMSObject it in objects)
                    {
                        Console.WriteLine(it.Name + " " + it.Description);
                    }
                }
                Thread.Sleep(1000);
                foreach (GXDLMSObject it in objects)
                {
                    // Profile generics are read later because they are special cases.
                    // (There might be so lots of data and we so not want waste time to read all the data.)
                    if (it is GXDLMSProfileGeneric)
                    {
                        continue;
                    }
                    if (!(it is IGXDLMSBase))
                    {
                        //If interface is not implemented.
                        //Example manufacturer spesific interface.
                        Console.WriteLine("Unknown Interface: " + it.ObjectType.ToString());
                        continue;
                    }
                    TraceLine(logFile, "-------- Reading " + it.GetType().Name + " " + it.Name + " " + it.Description);
                    foreach (int pos in (it as IGXDLMSBase).GetAttributeIndexToRead())
                    {
                        try
                        {
                            object val = comm.Read(it, pos);
                            //If data is array.
                            if (val is byte[])
                            {
                                val = GXCommon.ToHex((byte[])val, true);
                            }
                            else if (val is Array)
                            {
                                string str = "";
                                for (int pos2 = 0; pos2 != (val as Array).Length; ++pos2)
                                {
                                    if (str != "")
                                    {
                                        str += ", ";
                                    }
                                    if ((val as Array).GetValue(pos2) is byte[])
                                    {
                                        str += GXCommon.ToHex((byte[])(val as Array).GetValue(pos2), true);
                                    }
                                    else
                                    {
                                        str += (val as Array).GetValue(pos2).ToString();
                                    }
                                }
                                val = str;
                            }
                            else if (val is System.Collections.IList)
                            {
                                string str   = "[";
                                bool   empty = true;
                                foreach (object it2 in val as System.Collections.IList)
                                {
                                    if (!empty)
                                    {
                                        str += ", ";
                                    }
                                    empty = false;
                                    if (it2 is byte[])
                                    {
                                        str += GXCommon.ToHex((byte[])it2, true);
                                    }
                                    else
                                    {
                                        str += it2.ToString();
                                    }
                                }
                                str += "]";
                                val  = str;
                            }
                            TraceLine(logFile, "Index: " + pos + " Value: " + val);
                        }
                        catch (Exception ex)
                        {
                            TraceLine(logFile, "Error! Index: " + pos + " " + ex.Message);
                        }
                    }
                }
                Thread.Sleep(1000);
                //Find profile generics and read them.
                foreach (GXDLMSObject it in objects.GetObjects(ObjectType.ProfileGeneric))
                {
                    TraceLine(logFile, "-------- Reading " + it.GetType().Name + " " + it.Name + " " + it.Description);
                    long entriesInUse = Convert.ToInt64(comm.Read(it, 7));
                    long entries      = Convert.ToInt64(comm.Read(it, 8));
                    TraceLine(logFile, "Entries: " + entriesInUse + "/" + entries);
                    //If there are no columns or rows.
                    if (entriesInUse == 0 || (it as GXDLMSProfileGeneric).CaptureObjects.Count == 0)
                    {
                        continue;
                    }
                    try
                    {
                        //Read first row from Profile Generic.
                        object[]      rows = comm.ReadRowsByEntry(it as GXDLMSProfileGeneric, 0, 1);
                        StringBuilder sb   = new StringBuilder();
                        foreach (object[] row in rows)
                        {
                            foreach (object cell in row)
                            {
                                if (cell is byte[])
                                {
                                    sb.Append(GXCommon.ToHex((byte[])cell, true));
                                }
                                else
                                {
                                    sb.Append(Convert.ToString(cell));
                                }
                                sb.Append(" | ");
                            }
                            sb.Append("\r\n");
                        }
                        Trace(logFile, sb.ToString());
                    }
                    catch (Exception ex)
                    {
                        TraceLine(logFile, "Error! Failed to read first row: " + ex.Message);
                        //Continue reading.
                    }
                    try
                    {
                        //Read last day from Profile Generic.
                        object[]      rows = comm.ReadRowsByRange(it as GXDLMSProfileGeneric, DateTime.Now.Date, DateTime.MaxValue);
                        StringBuilder sb   = new StringBuilder();
                        foreach (object[] row in rows)
                        {
                            foreach (object cell in row)
                            {
                                if (cell is byte[])
                                {
                                    sb.Append(GXCommon.ToHex((byte[])cell, true));
                                }
                                else
                                {
                                    sb.Append(Convert.ToString(cell));
                                }
                                sb.Append(" | ");
                            }
                            sb.Append("\r\n");
                        }
                        Trace(logFile, sb.ToString());
                    }
                    catch (Exception ex)
                    {
                        TraceLine(logFile, "Error! Failed to read last day: " + ex.Message);
                        //Continue reading.
                    }
                }
                logFile.Flush();
                logFile.Close();
            }
            catch (Exception ex)
            {
                if (comm != null)
                {
                    comm.Close();
                }
                Console.WriteLine(ex.Message);
                if (!System.Diagnostics.Debugger.IsAttached)
                {
                    Console.ReadKey();
                }
            }
            finally
            {
                if (comm != null)
                {
                    comm.Close();
                }
                if (System.Diagnostics.Debugger.IsAttached)
                {
                    Console.WriteLine("Ended. Press any key to continue.");
                    Console.ReadKey();
                }
            }
        }
        public DevicePropertiesForm(GXManufacturerCollection manufacturers, GXDLMSDevice dev)
        {
            try
            {
                InitializeComponent();
                SecurityCB.Items.AddRange(new object[] { Security.None, Security.Authentication,
                                                         Security.Encryption, Security.AuthenticationEncryption });
                NetProtocolCB.Items.AddRange(new object[] { NetworkType.Tcp, NetworkType.Udp });
                this.ServerAddressTypeCB.SelectedIndexChanged += new System.EventHandler(this.ServerAddressTypeCB_SelectedIndexChanged);
                NetworkSettingsGB.Width      = this.Width - NetworkSettingsGB.Left;
                SerialSettingsGB.Bounds      = TerminalSettingsGB.Bounds = NetworkSettingsGB.Bounds;
                ServerAddressTypeCB.DrawMode = AuthenticationCB.DrawMode = DrawMode.OwnerDrawFixed;
                Manufacturers = manufacturers;
                //OK button is not enabled if there are no manufacturers.
                if (Manufacturers.Count == 0)
                {
                    OKBtn.Enabled = false;
                }
                //Show supported services tab only when they are read.
                if (dev == null || dev.Comm.client.SNSettings == null && dev.Comm.client.LNSettings == null)
                {
                    DeviceTab.TabPages.Remove(SupportedServicesTab);
                }
                else
                {
                    object settings = null;
                    if (dev.Comm.client.UseLogicalNameReferencing)
                    {
                        settings = dev.Comm.client.LNSettings;
                    }
                    else
                    {
                        settings = dev.Comm.client.SNSettings;
                    }
                    if (settings != null)
                    {
                        SupportedServicesGrid.SelectedObject = settings;
                        foreach (PropertyDescriptor it in TypeDescriptor.GetProperties(settings))
                        {
                            ReadOnlyAttribute att = (ReadOnlyAttribute)it.Attributes[typeof(ReadOnlyAttribute)];
                            if (att != null)
                            {
                                FieldInfo[] f = att.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
                                f[0].SetValue(att, true);
                            }
                        }
                    }
                }
                Device = dev;
                StartProtocolCB.Items.Add(StartProtocolType.IEC);
                StartProtocolCB.Items.Add(StartProtocolType.DLMS);
                int pos = 0;
                foreach (GXManufacturer it in Manufacturers)
                {
                    int index = this.ManufacturerCB.Items.Add(it);
                    if (it.Name == GXDLMSDirector.Properties.Settings.Default.SelectedManufacturer)
                    {
                        pos = index;
                    }
                }
                if (Device == null)
                {
                    Device = new GXDLMSDevice(null);
                    //Select first manufacturer.
                    if (Manufacturers.Count != 0)
                    {
                        ManufacturerCB.SelectedIndex = pos;
                    }
                }
                else
                {
                    foreach (GXManufacturer it in this.ManufacturerCB.Items)
                    {
                        if (string.Compare(it.Identification, Device.Manufacturer, true) == 0)
                        {
                            this.ManufacturerCB.SelectedItem = it;
                            break;
                        }
                    }
                    this.VerboseModeCB.Checked = dev.Verbose;
                    this.NameTB.Text           = dev.Name;
                    SelectedMedia                 = dev.Media;
                    UseRemoteSerialCB.Checked     = Device.UseRemoteSerial;
                    StartProtocolCB.SelectedItem  = Device.StartProtocol;
                    PhysicalServerAddressTB.Value = Convert.ToDecimal(Device.PhysicalAddress);
                    LogicalServerAddressTB.Value  = Convert.ToDecimal(Device.LogicalAddress);
                    this.ClientAddTB.Value        = Convert.ToDecimal(Convert.ToUInt32(Device.ClientAddress));
                    WaitTimeTB.Value              = Device.WaitTime;
                    SecurityCB.SelectedItem       = dev.Security;
                    SystemTitleTB.Text            = dev.SystemTitle;
                    BlockCipherKeyTB.Text         = dev.BlockCipherKey;
                    AuthenticationKeyTB.Text      = dev.AuthenticationKey;
                    UseUtcTimeZone.Checked        = Device.UtcTimeZone;
                }

                ManufacturerCB.DrawMode = MediasCB.DrawMode = DrawMode.OwnerDrawFixed;
                Gurux.Net.GXNet net = new Gurux.Net.GXNet();
                //Initialize network settings.
                if (SelectedMedia is GXNet)
                {
                    this.MediasCB.Items.Add(SelectedMedia);
                    net.Protocol               = Gurux.Net.NetworkType.Tcp;
                    this.HostNameTB.Text       = ((GXNet)SelectedMedia).HostName;
                    this.PortTB.Text           = ((GXNet)SelectedMedia).Port.ToString();
                    NetProtocolCB.SelectedItem = ((GXNet)SelectedMedia).Protocol;
                }
                else
                {
                    NetProtocolCB.SelectedItem = net.Protocol = Gurux.Net.NetworkType.Tcp;
                    this.MediasCB.Items.Add(net);
                }

                //Set maximum baud rate.
                GXSerial serial = new GXSerial();
                foreach (int it in serial.GetAvailableBaudRates(""))
                {
                    if (it != 0)
                    {
                        MaximumBaudRateCB.Items.Add(it);
                    }
                }
                if (Device.MaximumBaudRate == 0)
                {
                    UseMaximumBaudRateCB.Checked = false;
                    UseMaximumBaudRateCB_CheckedChanged(null, null);
                }
                else
                {
                    UseMaximumBaudRateCB.Checked        = true;
                    this.MaximumBaudRateCB.SelectedItem = Device.MaximumBaudRate;
                }

                if (SelectedMedia is GXSerial)
                {
                    this.MediasCB.Items.Add(SelectedMedia);
                    string[] ports = GXSerial.GetPortNames();
                    this.SerialPortCB.Items.AddRange(ports);
                    if (ports.Length != 0)
                    {
                        this.SerialPortCB.SelectedItem = ((GXSerial)SelectedMedia).PortName;
                    }
                }
                else
                {
                    //Initialize serial settings.
                    string[] ports = GXSerial.GetPortNames();
                    this.SerialPortCB.Items.AddRange(ports);
                    if (ports.Length != 0)
                    {
                        serial.PortName = ports[0];
                    }
                    if (((GXManufacturer)ManufacturerCB.SelectedItem).StartProtocol == StartProtocolType.DLMS)
                    {
                        serial.BaudRate = 9600;
                        serial.DataBits = 8;
                        serial.Parity   = Parity.None;
                        serial.StopBits = StopBits.One;
                    }
                    else
                    {
                        serial.BaudRate = 300;
                        serial.DataBits = 7;
                        serial.Parity   = Parity.Even;
                        serial.StopBits = StopBits.One;
                    }
                    this.MediasCB.Items.Add(serial);
                }
                if (SelectedMedia is Gurux.Terminal.GXTerminal)
                {
                    this.MediasCB.Items.Add(SelectedMedia);
                    string[] ports = GXTerminal.GetPortNames();
                    this.TerminalPortCB.Items.AddRange(ports);
                    if (ports.Length != 0)
                    {
                        this.TerminalPortCB.SelectedItem = ((Gurux.Terminal.GXTerminal)SelectedMedia).PortName;
                    }
                    this.TerminalPhoneNumberTB.Text = ((Gurux.Terminal.GXTerminal)SelectedMedia).PhoneNumber;
                }
                else
                {
                    //Initialize terminal settings.
                    Gurux.Terminal.GXTerminal termial = new Gurux.Terminal.GXTerminal();
                    string[] ports = GXTerminal.GetPortNames();
                    this.TerminalPortCB.Items.AddRange(ports);
                    if (ports.Length != 0)
                    {
                        termial.PortName = ports[0];
                    }
                    termial.BaudRate = 9600;
                    termial.DataBits = 8;
                    termial.Parity   = Parity.None;
                    termial.StopBits = StopBits.One;
                    this.TerminalPhoneNumberTB.Text = termial.PhoneNumber;
                    //termial.InitializeCommands = "AT+CBST=71,0,1\r\n";
                    this.MediasCB.Items.Add(termial);
                }
                //Select first media if medis is not selected.
                if (SelectedMedia == null)
                {
                    SelectedMedia = (Gurux.Common.IGXMedia) this.MediasCB.Items[0];
                }
                this.MediasCB.SelectedItem = SelectedMedia;
                if (!string.IsNullOrEmpty(Device.Password))
                {
                    this.PasswordTB.Text = ASCIIEncoding.ASCII.GetString(CryptHelper.Decrypt(Device.Password, Password.Key));
                }
                if (dev != null)
                {
                    this.UseLNCB.Checked = dev.UseLogicalNameReferencing;
                }
                this.AuthenticationCB.SelectedIndexChanged += new System.EventHandler(this.AuthenticationCB_SelectedIndexChanged);
                bool bConnected = Device.Media != null && Device.Media.IsOpen;
                SerialPortCB.Enabled         = AdvancedBtn.Enabled = ManufacturerCB.Enabled = MediasCB.Enabled =
                    AuthenticationCB.Enabled = UseRemoteSerialCB.Enabled = OKBtn.Enabled = !bConnected;
                HostNameTB.ReadOnly          = PortTB.ReadOnly = PasswordTB.ReadOnly = WaitTimeTB.ReadOnly = PhysicalServerAddressTB.ReadOnly = NameTB.ReadOnly = bConnected;
            }
            catch (Exception Ex)
            {
                GXDLMS.Common.Error.ShowError(this, Ex);
            }
        }
        private static void MainProcessing(object state)
        {
            IGXMedia media = null;
            GXCommunicatation comm = null;
            Gurux.Net.GXNet net = null;

            if ((!Environment.UserInteractive) && (args.Length == 0))	// when in service mode, get arguments from commandline if failed from onStart method
                args = Environment.CommandLine.Split(new char[] { ' ' });

            if (!Environment.UserInteractive && !running)
                return;

            try
            {
                logFile = new StreamWriter(File.Open(logFileName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite));
                logFile.WriteLine("\n");

                //Handle command line parameters.
                String id = "lgz", host = "", port = "4095", pw = "";
                String lt = "-1";
                bool trace = false, iec = true;
                int loopTime = -1;
                Authentication auth = Authentication.None;
                foreach (string it in args)
                {
                    String item = it.Trim().ToLower();
                    if (string.Compare(item, "/u", true) == 0)//Update
                    {
                        //Get latest manufacturer settings from Gurux web server.
                        GXManufacturerCollection.UpdateManufactureSettings();
                    }
                    else if (item.StartsWith("/m="))//Manufacturer
                    {
                        id = item.Replace("/m=", "");
                    }
                    else if (item.StartsWith("/host=")) //Host
                    {
                        host = item.Replace("/host=", "");
                    }
                    else if (item.StartsWith("/p="))// TCP/IP Port
                    {
                        media = new Gurux.Net.GXNet();
                        port = item.Replace("/p=", "");
                    }
                    else if (item.StartsWith("/sp="))//Serial Port
                    {
                        port = item.Replace("/sp=", "");
                        media = new GXSerial();
                    }
                    else if (item.StartsWith("/t"))//Are messages traced.
                    {
                        trace = true;
                    }
                    else if (item.StartsWith("/s="))//Start
                    {
                        String tmp = item.Replace("/s=", "");
                        iec = string.Compare(tmp, "dlms", true) != 0;
                    }
                    else if (item.StartsWith("/a="))//Authentication
                    {
                        auth = (Authentication)Enum.Parse(typeof(Authentication), it.Trim().Replace("/a=", ""));
                    }
                    else if (item.StartsWith("/pw="))//Password
                    {
                        pw = it.Trim().Replace("/pw=", "");
                    }
                    else if (item.StartsWith("/l="))// loop time
                    {
                        lt = item.Replace("/l=", "");
                    }
                    else if (item.StartsWith("/h"))// help
                    {
                        ShowHelp();
                        return;
                    }
                    else if (item.StartsWith("/sm=")) //sitemap
                    {
                        sitesMapPath = it.Trim().Replace("/sm=", "");
                    }
                    else if (item.StartsWith("/is=")) //IAM server
                    {
                        IAMServer = it.Trim().Replace("/is=", "");
                    }
                }
                if (media == null)
                    media = new Gurux.Net.GXNet();

                int.TryParse(lt, out loopTime);

                Version version = Assembly.GetExecutingAssembly().GetName().Version;

                if (!Environment.UserInteractive)
                    TraceLine(logFile, string.Format("IAM Reader OPEN SOURCE EXAMPLE Service ver. {0} started with loop time={1} min.", version.ToString(3), loopTime));
                else
                    TraceLine(logFile, string.Format("IAM Reader OPEN SOURCE EXAMPLE ver. {0} started with loop time={1} min.", version.ToString(3), loopTime));

                logFile.Flush();

                //Initialize connection settings.
                if (media is GXSerial)
                {
                    GXSerial serial = media as GXSerial;
                    serial.PortName = port;
                    if (iec)
                    {
                        serial.BaudRate = 300;
                        serial.DataBits = 7;
                        serial.Parity = System.IO.Ports.Parity.Even;
                        serial.StopBits = System.IO.Ports.StopBits.One;
                    }
                    else
                    {
                        serial.BaudRate = 9600;
                        serial.DataBits = 8;
                        serial.Parity = System.IO.Ports.Parity.None;
                        serial.StopBits = System.IO.Ports.StopBits.One;
                    }
                }
                else if (media is GXNet)
                {
                    /*Gurux.Net.GXNet*/
                    net = media as GXNet;
                    net.Port = Convert.ToInt32(port);
                    net.HostName = host;
                    net.Protocol = Gurux.Net.NetworkType.Tcp;
                }
                else
                {
                    throw new Exception("Unknown media type.");
                }

                //Update manufacturer debended settings.
                GXManufacturerCollection Manufacturers = new GXManufacturerCollection();
                GXManufacturerCollection.ReadManufacturerSettings(Manufacturers);
                GXManufacturer man = Manufacturers.FindByIdentification(id);
                if (man == null)
                {
                    throw new Exception("Unknown manufacturer: " + id);
                }
                GXDLMSClient dlms = new GXDLMSClient();
                //Update Obis code list so we can get right descriptions to the objects.
                dlms.ObisCodes = man.ObisCodes;

                List<IAM.DLMSSite> DlmsSites = null;
                IAM.ArrayOfDLMSSite aods = null;

                XmlSerializer y = new XmlSerializer(typeof(IAM.ArrayOfDLMSSite));
                if (File.Exists(sitesMapPath))
                {
                    try
                    {
                        using (Stream stream = File.Open(sitesMapPath, FileMode.Open))
                        {
                            TraceLine(logFile, "Get configured sites map from file.");
                            aods = y.Deserialize(stream) as IAM.ArrayOfDLMSSite;
                            DlmsSites = aods.DLMSSite;
                            stream.Close();
                        }

                    }
                    catch (Exception ex)
                    {
                        throw ex;
                    }
                }
                else
                {
                    TraceLine(logFile, "Error. SitesMap file not found.");
                    return;
                }

                List<Type> extraTypes = new List<Type>(Gurux.DLMS.GXDLMSClient.GetObjectTypes());
                extraTypes.Add(typeof(GXDLMSAttributeSettings));
                extraTypes.Add(typeof(GXDLMSAttribute));
                //TraceLine(logFile, "Memory32: " + GC.GetTotalMemory(true));
                XmlSerializer x = new XmlSerializer(typeof(GXDLMSObjectCollection), extraTypes.ToArray());
                //You can save association view, but make sure that it is not change.
                //Save Association view to the cache so it is not needed to retrieve every time.
                extraTypes.Clear();

                foreach (IAM.DLMSSite site in DlmsSites) //
                {
                    site.DataProcessing.EnergyPeriodDateTime = DateTime.MinValue;
                    site.DataProcessing.PowerPeriodDateTime = DateTime.MinValue;
                }

                //bool keyAvailable = false;
                DateTime startTime;
                FileInfo infoFileSite = new FileInfo(sitesMapPath);
                DateTime lastWriteMapFile = infoFileSite.LastWriteTime;

                do
                {
                    try
                    {
                        FileInfo f = new FileInfo(logFileName); //output log file
                        if (f.Length > maxLogFileSize)
                        {
                            logFile.Flush();
                            logFile.Close();
                            File.Delete(rotatedLogFileName);
                            File.Move(logFileName, rotatedLogFileName);
                            logFile = new StreamWriter(File.Open(logFileName, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite));
                        }

                        infoFileSite.Refresh();
                        if (infoFileSite.LastWriteTime != lastWriteMapFile)
                        {
                            try
                            {
                                using (Stream stream = File.Open(sitesMapPath, FileMode.Open))
                                {
                                    TraceLine(logFile, "Get updated sites map from file.");
                                    aods = y.Deserialize(stream) as IAM.ArrayOfDLMSSite;
                                    DlmsSites = aods.DLMSSite;
                                    stream.Close();

                                    lastWriteMapFile = infoFileSite.LastWriteTime;
                                }

                            }
                            catch (Exception ex)
                            {
                                throw ex;
                            }

                        }

                        startTime = DateTime.Now;
                        TraceLine(logFile, "Start new iteration");
                        foreach (IAM.DLMSSite site in DlmsSites) //cycle for each remote meter (listed in the sitemap.xml)
                        {
                            TraceLine(logFile, "Now processing: " + site.Name); //current remote meter
                            if (!site.Enabled)
                            {
                                TraceLine(logFile, "Disabled: skip to next");
                                continue;
                            }
                            try
                            {
                                host = site.Device.Host; //ip address of the current remote meter
                                port = site.Device.Port;
                                if (site.Device.Manufacturer != "")
                                    id = site.Device.Manufacturer.ToLower();
                                if (site.Device.Protocol != "")
                                    iec = site.Device.Protocol.ToLower() == "dlms";
                                if (media is GXNet)
                                {
                                    /*Gurux.Net.GXNet*/
                                    net = media as GXNet;
                                    net.Port = Convert.ToInt32(port);
                                    net.HostName = host;
                                    net.Protocol = Gurux.Net.NetworkType.Tcp;
                                }
                                comm = new GXCommunicatation(dlms, media, iec, auth, pw);
                                comm.Trace = trace;
                                TraceLine(logFile, "Initializing Network connection.");
                                comm.InitializeConnection(man);
                            }
                            catch (Exception ex)
                            {
                                TraceLine(logFile, "Error. " + ex.Message);
                                if (comm != null)
                                {
                                    comm.Close();
                                }
                                continue;
                            }
                            GXDLMSObjectCollection objects = null;

                            string meterPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) +  "\\" +host.Replace('.', '_') + "_" + port.ToString() + ".xml";

                            if (File.Exists(meterPath)) //list of OBIS objects for remote meter
                            {
                                try
                                {
                                    using (Stream stream = File.Open(meterPath, FileMode.Open))
                                    {
                                        TraceLine(logFile, "Get available objects from the cache.");
                                        objects = x.Deserialize(stream) as GXDLMSObjectCollection;
                                        stream.Close();
                                    }

                                }
                                catch (Exception ex)
                                {
                                    if (File.Exists(meterPath))
                                    {
                                        File.Delete(meterPath);
                                    }
                                    throw ex;
                                }
                            }
                            else
                            {
                                TraceLine(logFile, "Get available objects from the device.");
                                objects = comm.GetAssociationView();

                                // Save to file
                                try
                                {
                                    using (Stream stream = File.Open(meterPath, FileMode.Create))
                                    {
                                        TextWriter writer = new StreamWriter(stream);
                                        x.Serialize(writer, objects);
                                        writer.Close();
                                        stream.Close();
                                    }
                                    TraceLine(logFile, "Available objects saved to the cache.");

                                }
                                catch (Exception ex)
                                {
                                    if (File.Exists(meterPath))
                                    {
                                        File.Delete(meterPath);
                                    }
                                    throw ex;
                                }

                            }

                            // start remote meter reading
                            try
                            {
                                int EPeriod = 15;	// energy integration period
                                if (site.DataProcessing.EnergyPeriod != 0)
                                    EPeriod = site.DataProcessing.EnergyPeriod;
                                else
                                    site.DataProcessing.EnergyPeriod = EPeriod;

                                //if (EPeriod <= 0)
                                //    EPeriod = 15;

                                int PPeriod = 15;	// power integration period
                                if (site.DataProcessing.PowerPeriod != 0)
                                    PPeriod = site.DataProcessing.PowerPeriod;
                                else
                                    site.DataProcessing.PowerPeriod = PPeriod;

                                //if (PPeriod <= 0)
                                //    PPeriod = 15;

                                DateTime now = DateTime.Now;
                                DateTime nowRnd = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute / EPeriod * EPeriod, 0);

                                if (site.DataProcessing.EnergyPeriodDateTime == DateTime.MinValue)
                                {
                                    site.DataProcessing.EnergyPeriodDateTime = now;
                                    TraceLine(logFile, "Initialize energy period from null.");
                                }

                                // default OBIS codes for energies
                                string AEP = "1.0.1.8.0.255";
                                string AEM = "1.0.2.8.0.255";
                                string REP = "1.0.3.8.0.255";
                                string REM = "1.0.4.8.0.255";

                                if (!string.IsNullOrEmpty(site.ArrayOfOBIS.DataObjects.ActiveEnergyP)) //plus = absorbed energy
                                    AEP = site.ArrayOfOBIS.DataObjects.ActiveEnergyP;
                                if (!string.IsNullOrEmpty(site.ArrayOfOBIS.DataObjects.ActiveEnergyM)) //minus = supplied energy
                                    AEM = site.ArrayOfOBIS.DataObjects.ActiveEnergyM;
                                if (!string.IsNullOrEmpty(site.ArrayOfOBIS.DataObjects.ReactiveEnergyP)) //plus = absorbed energy
                                    REP = site.ArrayOfOBIS.DataObjects.ReactiveEnergyP;
                                if (!string.IsNullOrEmpty(site.ArrayOfOBIS.DataObjects.ReactiveEnergyM)) //minus = supplied energy
                                    REM = site.ArrayOfOBIS.DataObjects.ReactiveEnergyM;

                                GXDLMSObject aepObj = objects.FindByLN(ObjectType.Register, AEP);
                                if (aepObj == null)
                                    throw new System.InvalidOperationException(string.Format("Error: Active Energy Positive Object not defined for site {0}.", site.Name));
                                GXDLMSObject aemObj = objects.FindByLN(ObjectType.Register, AEM);
                                if (aemObj == null)
                                    throw new System.InvalidOperationException(string.Format("Active Energy Negative Object not defined for site {0}.", site.Name));
                                GXDLMSObject repObj = objects.FindByLN(ObjectType.Register, REP);
                                if (repObj == null)
                                    throw new System.InvalidOperationException(string.Format("Reactive Energy Positive Object not defined for site {0}.", site.Name));
                                GXDLMSObject remObj = objects.FindByLN(ObjectType.Register, REM);
                                if (remObj == null)
                                    throw new System.InvalidOperationException(string.Format("Reactive Energy Negative Object not defined for site {0}.", site.Name));

                                Regex regex = new Regex(@"^Scaler:(.*) Unit:(.*)$");
                                double scaler = 1;

                                object value = comm.Read(aepObj, 2);
                                string scalerAttr = (string)comm.Read(aepObj, 3);
                                Match match = regex.Match(scalerAttr);
                                if (match.Groups.Count >= 2)
                                    scaler = double.Parse(match.Groups[1].Value);
                                double ActiveEnergyP = double.Parse(value.ToString()) * scaler;
                                TraceLine(logFile, "Positive Active Energy reading completed.");

                                value = comm.Read(aemObj, 2);
                                scalerAttr = (string)comm.Read(aemObj, 3);
                                match = regex.Match(scalerAttr);
                                if (match.Groups.Count >= 2)
                                    scaler = double.Parse(match.Groups[1].Value);
                                double ActiveEnergyM = double.Parse(value.ToString()) * scaler;
                                TraceLine(logFile, "Negative Active Energy reading completed.");

                                value = comm.Read(repObj, 2);
                                scalerAttr = (string)comm.Read(repObj, 3);
                                match = regex.Match(scalerAttr);
                                if (match.Groups.Count >= 2)
                                    scaler = double.Parse(match.Groups[1].Value);
                                double ReactiveEnergyP = double.Parse(value.ToString()) * scaler;
                                TraceLine(logFile, "Positive Reactive Energy reading completed.");

                                value = comm.Read(remObj, 2);
                                scalerAttr = (string)comm.Read(remObj, 3);
                                match = regex.Match(scalerAttr);
                                if (match.Groups.Count >= 2)
                                    scaler = double.Parse(match.Groups[1].Value);
                                double ReactiveEnergyM = double.Parse(value.ToString()) * scaler;
                                TraceLine(logFile, "Negative Reactive Energy reading completed.");

                                // end of remote meter reading

                                if (site.DataProcessing.ActiveEnergyPStart == 0)
                                    site.DataProcessing.ActiveEnergyPStart = ActiveEnergyP;
                                site.DataProcessing.ActiveEnergyPCurrent = ActiveEnergyP;

                                if (site.DataProcessing.ActiveEnergyMStart == 0)
                                    site.DataProcessing.ActiveEnergyMStart = ActiveEnergyM;
                                site.DataProcessing.ActiveEnergyMCurrent = ActiveEnergyM;

                                if (site.DataProcessing.ReactiveEnergyPStart == 0)
                                    site.DataProcessing.ReactiveEnergyPStart = ReactiveEnergyP;
                                site.DataProcessing.ReactiveEnergyPCurrent = ReactiveEnergyP;

                                if (site.DataProcessing.ReactiveEnergyMStart == 0)
                                    site.DataProcessing.ReactiveEnergyMStart = ReactiveEnergyM;
                                site.DataProcessing.ReactiveEnergyMCurrent = ReactiveEnergyM;

                                DateTime tStart = new DateTime(site.DataProcessing.EnergyPeriodDateTime.Year, site.DataProcessing.EnergyPeriodDateTime.Month, site.DataProcessing.EnergyPeriodDateTime.Day, site.DataProcessing.EnergyPeriodDateTime.Hour, site.DataProcessing.EnergyPeriodDateTime.Minute / EPeriod * EPeriod, 0);
                                TimeSpan ts = now.Subtract(tStart);

                                if (EPeriod > 0)		// if energy recording enabled
                                {
                                    if (((ts.Hours * 60) + ts.Minutes) >= EPeriod)  // if end of period
                                    {
                                        ts = now.Subtract(site.DataProcessing.EnergyPeriodDateTime);
                                        double ratio = (double)((ts.Hours * 3600) + (ts.Minutes * 60) + ts.Seconds) / (EPeriod * 60);
                                        if (ratio > 0.9) ratio = 1;
                                        ratio = Math.Round(ratio, 2);
                                        TraceLine(logFile, string.Format("End of integration energy period (ratio = {0})", ratio));

                                        double deltaActiveEnergyP = site.DataProcessing.ActiveEnergyPCurrent - site.DataProcessing.ActiveEnergyPStart;
                                        double deltaActiveEnergyM = site.DataProcessing.ActiveEnergyMCurrent - site.DataProcessing.ActiveEnergyMStart;

                                        double deltaReactiveEnergyP = site.DataProcessing.ReactiveEnergyPCurrent - site.DataProcessing.ReactiveEnergyPStart;
                                        double deltaReactiveEnergyM = site.DataProcessing.ReactiveEnergyMCurrent - site.DataProcessing.ReactiveEnergyMStart;

                                        if (deltaActiveEnergyP > deltaActiveEnergyM)	// quadrants prevalent: I or IV
                                        {
                                            PublishEnergy(site, nowRnd, deltaActiveEnergyP, deltaActiveEnergyM, deltaReactiveEnergyP, 0, 0, deltaReactiveEnergyM, ratio, logFile);
                                        }
                                        else  // quadrants prevalent: II or III
                                        {
                                            PublishEnergy(site, nowRnd, deltaActiveEnergyP, deltaActiveEnergyM, 0, deltaReactiveEnergyP, deltaReactiveEnergyM, 0, ratio, logFile);
                                        }

                                        site.DataProcessing.EnergyPeriodDateTime = now;
                                        site.DataProcessing.ActiveEnergyPStart = ActiveEnergyP;
                                        site.DataProcessing.ActiveEnergyMStart = ActiveEnergyM;
                                        site.DataProcessing.ReactiveEnergyPStart = ReactiveEnergyP;
                                        site.DataProcessing.ReactiveEnergyMStart = ReactiveEnergyM;
                                    }
                                }

                                if (site.DataProcessing.ActivePowerPStart == 0)
                                    site.DataProcessing.ActivePowerPStart = ActiveEnergyP;
                                site.DataProcessing.ActivePowerPCurrent = ActiveEnergyP;

                                if (site.DataProcessing.ActivePowerMStart == 0)
                                    site.DataProcessing.ActivePowerMStart = ActiveEnergyM;
                                site.DataProcessing.ActivePowerMCurrent = ActiveEnergyM;

                                if (site.DataProcessing.ReactivePowerPStart == 0)
                                    site.DataProcessing.ReactivePowerPStart = ReactiveEnergyP;
                                site.DataProcessing.ReactivePowerPCurrent = ReactiveEnergyP;

                                if (site.DataProcessing.ReactivePowerMStart == 0)
                                    site.DataProcessing.ReactivePowerMStart = ReactiveEnergyM;
                                site.DataProcessing.ReactivePowerMCurrent = ReactiveEnergyM;

                                tStart = new DateTime(site.DataProcessing.PowerPeriodDateTime.Year, site.DataProcessing.PowerPeriodDateTime.Month, site.DataProcessing.PowerPeriodDateTime.Day, site.DataProcessing.PowerPeriodDateTime.Hour, site.DataProcessing.PowerPeriodDateTime.Minute / PPeriod * PPeriod, 0);
                                ts = now.Subtract(tStart);

                                if (PPeriod > 0)		// if power recording enabled
                                {
                                    if (((ts.Hours * 60) + ts.Minutes) >= PPeriod)  // if end of period
                                    {
                                        ts = now.Subtract(site.DataProcessing.PowerPeriodDateTime);
                                        double ratio = (double)((ts.Hours * 3600) + (ts.Minutes * 60) + ts.Seconds) / (PPeriod * 60);
                                        if (ratio > 0.9) ratio = 1;
                                        ratio = Math.Round(ratio, 2);
                                        TraceLine(logFile, string.Format("End of integration power period (ratio = {0})", ratio));

                                        double deltaActivePowerP = (site.DataProcessing.ActivePowerPCurrent - site.DataProcessing.ActivePowerPStart) / PPeriod * 60;
                                        double deltaActivePowerM = (site.DataProcessing.ActivePowerMCurrent - site.DataProcessing.ActivePowerMStart) / PPeriod * 60;

                                        double deltaReactivePowerP = (site.DataProcessing.ReactivePowerPCurrent - site.DataProcessing.ReactivePowerPStart) / PPeriod * 60;
                                        double deltaReactivePowerM = (site.DataProcessing.ReactivePowerMCurrent - site.DataProcessing.ReactivePowerMStart) / PPeriod * 60;

                                        // since ZXF meter has no capability to supply Q1-Q4 (but only 2 quadrants), we calculate Q1, Q2, Q3, Q4 here

                                        if (deltaActivePowerP > deltaActivePowerM)	// quadrants prevalent: I or IV
                                        {
                                            PublishPower(site, nowRnd, deltaActivePowerP, deltaActivePowerM, deltaReactivePowerP, 0, 0, deltaReactivePowerM, ratio, logFile);
                                        }
                                        else  // quadrants prevalent: II or III
                                        {
                                            PublishPower(site, nowRnd, deltaActivePowerP, deltaActivePowerM, 0, deltaReactivePowerP, deltaReactivePowerM, 0, ratio, logFile);
                                        }

                                        //

                                        site.DataProcessing.PowerPeriodDateTime = now;
                                        site.DataProcessing.ActivePowerPStart = ActiveEnergyP;
                                        site.DataProcessing.ActivePowerMStart = ActiveEnergyM;
                                        site.DataProcessing.ReactivePowerPStart = ReactiveEnergyP;
                                        site.DataProcessing.ReactivePowerMStart = ReactiveEnergyM;
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                TraceLine(logFile, "Error. " + ex.Message);
                                if (comm != null)
                                {
                                    comm.Close();
                                }
                                continue;
                            }

            #if ZERO
                            foreach (GXDLMSObject it in objects)
                            {
                                if (!string.IsNullOrEmpty(site.ArrayOfOBIS.DataObjects.ActiveEnergyP))		// if is requested the ActiveEnergy+ obis code
                                {

                                    if (it.LogicalName == AEP)
                                    {
                                        try
                                        {
                                            object value = comm.Read(it, 2);
                                            string scalerAttr = (string)comm.Read(it, 3);

                                            Regex regex = new Regex(@"^Scaler:(.*) Unit:(.*)$");
                                            Match match = regex.Match(scalerAttr);

                                            double scaler = 1;
                                            if (match.Groups.Count >= 2)
                                                scaler = double.Parse(match.Groups[1].Value);

                                            double Energy = double.Parse(value.ToString()) * scaler;

                                            // First time initialize the value of initial energy
                                            if (site.DataProcessing.ActiveEnergyPStart == 0)
                                            {
                                                site.DataProcessing.ActiveEnergyPStart = Energy;
                                                TraceLine(logFile, "Initial ActiveEnergy+ : " + Energy + " Wh");
                                            }
                                        }
                                        catch (Exception ex)
                                        {
                                            TraceLine(logFile, "Error. Failed to get ActiveEnergy+: " + ex.Message);
                                            //Continue reading.
                                        }

                                    }
                                }

                                // Read meter inst. values
                                if (!string.IsNullOrEmpty(site.ArrayOfOBIS.DataObjects.ActivePower))
                                {
                                    try
                                    {

                                        if (it.LogicalName == site.ArrayOfOBIS.DataObjects.ActivePower)
                                        {
                                            //Console.WriteLine(it.Name);
                                            object value = comm.Read(it, 2);
                                            string scalerAttr = (string)comm.Read(it, 3);

                                            Regex regex = new Regex(@"^Scaler:(.*) Unit:(.*)$");
                                            Match match = regex.Match(scalerAttr);

                                            double scaler = 1;
                                            if (match.Groups.Count >= 2)
                                                scaler = double.Parse(match.Groups[1].Value);

                                            double activePower = double.Parse(value.ToString()) * scaler;
                                            TraceLine(logFile, "Active Power: " + activePower + " W");

                                            int period = 15;
                                            if (site.DataProcessing.Period != 0)
                                            {
                                                period = site.DataProcessing.Period;
                                            }
                                            DateTime now = DateTime.Now;
                                            DateTime nowRnd = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute / period * period, 0);

                                            if (site.DataProcessing.IntervalDateTime.Ticks == 0)
                                            {
                                                site.DataProcessing.IntervalDateTime = nowRnd;
                                                site.DataProcessing.Count = 0;
                                                site.DataProcessing.Sum = 0;
                                                TraceLine(logFile, "Initialize period from null.");
                                            }
                                            else
                                            {
                                                long elapsedTicks = now.Ticks - site.DataProcessing.IntervalDateTime.Ticks;
                                                TimeSpan elapsedSpan = new TimeSpan(elapsedTicks);
                                                if (elapsedSpan.TotalMinutes >= period)  // if end of period
                                                {
                                                    // Round date to minute multiple of "period"
                                                    if (site.DataProcessing.Count > 0)    // compute avg quantities
                                                    {
                                                        TraceLine(logFile, "End of inst. readings integration period.");
                                                        double avgActivePower = site.DataProcessing.Sum / site.DataProcessing.Count;
                                                        site.DataProcessing.IntervalDateTime = nowRnd;
                                                        site.DataProcessing.Count = 0;
                                                        site.DataProcessing.Sum = 0;
                                                        //                                                    PublishReading(site, site.DataProcessing.IntervalDateTime.AddMinutes(period), avgActivePower, logFile);
                                                        PublishReading(site, site.DataProcessing.IntervalDateTime, avgActivePower, 0, 0, 0, 0, 0, logFile);
                                                    }
                                                    else
                                                    {
                                                        TraceLine(logFile, "Zero counts period: initialize only.");
                                                        site.DataProcessing.IntervalDateTime = nowRnd;
                                                        site.DataProcessing.Count = 0;
                                                        site.DataProcessing.Sum = 0;
                                                    }
                                                }
                                                site.DataProcessing.Sum += activePower;
                                                site.DataProcessing.Count++;
                                            }
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        TraceLine(logFile, "Error. Failed to get inst. readings: " + ex.Message);
                                        //Continue reading.
                                    }
                                }

                                //  Read load profiles
                                if (string.IsNullOrEmpty(site.ArrayOfOBIS.GenericProfileObjects.LoadProfile))
                                    continue;

                                if (it.LogicalName == site.ArrayOfOBIS.GenericProfileObjects.LoadProfile)
                                {
                                    //Console.WriteLine(it.Name);
                                    try
                                    {
                                        int period = 15;
                                        if (site.DataProcessing.ProfilePeriod != 0)
                                        {
                                            period = site.DataProcessing.ProfilePeriod;
                                        }

                                        DateTime now = DateTime.Now;
                                        DateTime nowRnd = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute / period * period, 0);
                                        long elapsedTicks = now.Ticks - site.DataProcessing.ProfileDateTime.Ticks;
                                        TimeSpan elapsedSpan = new TimeSpan(elapsedTicks);
                                        double totalMinutes = elapsedSpan.TotalMinutes;
                                        int maxDays = 1;
                                        if (totalMinutes > 1440 * maxDays)
                                        {  // max one week
                                            totalMinutes = 1440 * maxDays;
                                            site.DataProcessing.ProfileDateTime = nowRnd.AddMinutes(-totalMinutes);
                                        }
                                        if (totalMinutes >= period)  // if end of period
                                        {
                                            //Read from Profile Generic.
                                            object[] rows = comm.ReadRowsByRange(it, site.DataProcessing.ProfileDateTime, nowRnd, (it as GXDLMSProfileGeneric).CaptureObjects);
                                            StringBuilder sb = new StringBuilder();
                                            foreach (object[] row in rows)
                                            {
                                                object dto = row[0];
                                                DateTime dt;
                                                if (DateTime.TryParse(dto.ToString(), out dt))
                                                {
                                                    dt = dt.ToLocalTime();
                                                    row[0] = dt;
                                                }

                                                foreach (object cell in row)
                                                {
                                                    if (cell is byte[])
                                                    {
                                                        sb.Append(GXCommon.ToHex((byte[])cell, true));
                                                    }
                                                    else
                                                    {
                                                        sb.Append(Convert.ToString(cell));
                                                    }
                                                    sb.Append(" | ");
                                                }
                                                sb.Append("\r\n");
                                            }
                                            site.DataProcessing.ProfileDateTime = nowRnd;
                                            PublishProfile(site, site.DataProcessing.ProfileDateTime, sb, logFile);
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        TraceLine(logFile, "Error. Failed to get load profile: " + ex.Message);
                                        //Continue reading.
                                    }
                                }
                            }
            #endif
                            try
                            {
                                using (Stream stream = File.Open(sitesMapPath, FileMode.Create))
                                {
                                    TraceLine(logFile, "Save site map to file.");
                                    TextWriter writer = new StreamWriter(stream);
                                    y.Serialize(writer, aods);
                                    //                            aods = y.Deserialize(stream) as IAM.ArrayOfDLMSSite;
                                    stream.Close();

                                    infoFileSite.Refresh();
                                    lastWriteMapFile = infoFileSite.LastWriteTime;
                                }

                            }
                            catch (Exception ex)
                            {
                                throw ex;
                            }

                            TraceLine(logFile, "Disconnecting from the meter.");
                            comm.Close();
                            objects.Clear();
                        }
                    }
                    catch (Exception ex)
                    {
                        TraceLine(logFile, ex.Message);
                        if (comm != null)
                        {
                            comm.Close();
                        }
                        // Continue reading
                    }

                    logFile.Flush();

                    if (loopTime > 0)   // wait until next loop time
                    {
                        DateTime when = DateTime.Now;
                        int nextMinutes = (when.Minute / loopTime) * loopTime + loopTime;
                        DateTime nextTime = new DateTime(when.Year, when.Month, when.Day);
                        nextTime = nextTime.AddHours(when.Hour);
                        nextTime = nextTime.AddMinutes(nextMinutes);
                        int waitSeconds = (int)(new TimeSpan(nextTime.Ticks - when.Ticks).TotalSeconds);
                        waitSeconds++;
                        TraceLine(logFile, "Waiting for next loop (in "+waitSeconds+" sec.)...\r\n");
                        logFile.Flush();
                        do
                        {
                            Thread.Sleep(1000);
                            waitSeconds--;

                            //if (Environment.UserInteractive)
                            //    keyAvailable = Console.KeyAvailable;

                        } while ((waitSeconds > 0) && !keyAvailable && running);
                    }
                    Console.WriteLine("");

                    //if (Environment.UserInteractive)
                    //    keyAvailable = Console.KeyAvailable;

                } while (!keyAvailable && (loopTime != -1) && running);

                if (keyAvailable)
                {
                    TraceLine(logFile, "Program interrupted by user.");
                }
                else if (!running)
                {
                    TraceLine(logFile, "Service stopped.");
                }
                else
                {
                    TraceLine(logFile, "Single run ended.");
                    if (!Environment.UserInteractive)
                    {
                        logFile.Flush();
                        logFile.Close();
                        Environment.Exit(0);
                    }
                }
            }
            catch (Exception ex)
            {
                if (logFile != null)
                    TraceLine(logFile, ex.Message);

                if (comm != null)
                {
                    comm.Close();
                }
                Console.WriteLine("Error. " + ex.Message);
            }
            finally
            {
                logFile.Flush();
                logFile.Close();

                if (comm != null)
                {
                    comm.Close();
                }
                Console.WriteLine("Now stop.");
            }
        }