private static void EnsureNode(byte nodeAddr)
        {
            var childName = $"Node{nodeAddr}";

            DictModbusItems.TryAdd(childName, new ModbusNode {
                Key = childName
            });
        }
        private static void EnsureModbusAI(byte nodeAddr, int addr)
        {
            EnsureNode(nodeAddr);
            var childName = $"Node{nodeAddr}.AI{addr}";

            DictModbusItems.TryAdd(childName, new ModbusAnalogInput {
                Key = childName
            });
        }
        private static void EnsureModbusHR(byte nodeAddr, int addr)
        {
            EnsureNode(nodeAddr);
            var childName = $"Node{nodeAddr}.HR{addr}";

            DictModbusItems.TryAdd(childName, new ModbusHoldingRegister {
                Key = childName
            });
        }
        static void Worker_DoWork(object sender, DoWorkEventArgs e)
        {
            var worker = (BackgroundWorker)sender;

            //var lastsecond = DateTime.Now.Second;
            //var lastminute = -1;
            //var lasthour = -1;

            //while (!worker.CancellationPending)
            //{
            //    var dt = DateTime.Now;
            //    if (lastsecond == dt.Second) continue;
            //    lastsecond = dt.Second;
            //    // прошла секунда
            //    //worker.ReportProgress(lastsecond, $"{dt.Second} секунда");

            //    if (lastminute == dt.Minute) continue;
            //    lastminute = dt.Minute;
            //    // прошла минута
            //    worker.ReportProgress(lastminute, $"{dt.Minute} минута");

            //    if (lasthour != dt.Hour && dt.Minute == 0)
            //    {
            //        lasthour = dt.Hour;
            //        // здесь закрываем предыдущий час
            //    }
            //}

            #region работа с Tcp портом

            var tt = e.Argument as TcpTuning;
            if (tt != null)
            {
                const int socketTimeOut = 90000;
                var       listener      = new TcpListener(IPAddress.Any, tt.Port)
                {
                    Server = { SendTimeout = socketTimeOut, ReceiveTimeout = socketTimeOut }
                };
                Thread.Sleep(100);
                Say(worker, $"\nСокет localhost:{tt.Port} прослушивается...");
                do
                {
                    Thread.Sleep(1);
                    try
                    {
                        listener.Start(10);
                        // Buffer for reading data
                        var bytes = new byte[256];

                        while (!listener.Pending())
                        {
                            Thread.Sleep(1);
                            if (!worker.CancellationPending)
                            {
                                continue;
                            }
                            listener.Stop();
                            e.Cancel = true;
                            Say(worker, $"\nСокет TCP({tt.Port}) - остановка прослушивания.");
                            return;
                        }
                        var clientData = listener.AcceptTcpClient();
                        // создаем отдельный поток для каждого подключения клиента
                        ThreadPool.QueueUserWorkItem(arg =>
                        {
                            try
                            {
                                // Get a stream object for reading and writing
                                var stream = clientData.GetStream();
                                int count;
                                // Loop to receive all the data sent by the client.
                                while ((count = stream.Read(bytes, 0, bytes.Length)) != 0)
                                {
                                    //Thread.Sleep(1);
                                    var list = new List <string>();
                                    for (var i = 0; i < count; i++)
                                    {
                                        list.Add(string.Format("{0}", bytes[i]));
                                    }
                                    //Say("Q:" + string.Join(",", list));

                                    if (count < 6)
                                    {
                                        continue;
                                    }
                                    var header1   = Convert.ToUInt16(bytes[0] * 256 + bytes[1]);
                                    var header2   = Convert.ToUInt16(bytes[2] * 256 + bytes[3]);
                                    var packetLen = Convert.ToUInt16(bytes[4] * 256 + bytes[5]);
                                    if (count != packetLen + 6)
                                    {
                                        continue;
                                    }
                                    var nodeAddr    = bytes[6];
                                    var funcCode    = bytes[7];
                                    var startAddr   = Convert.ToUInt16(bytes[8] * 256 + bytes[9]);
                                    var regCount    = Convert.ToUInt16(bytes[10] * 256 + bytes[11]);
                                    var singleValue = Convert.ToUInt16(bytes[10] * 256 + bytes[11]);
                                    EnsureNode(nodeAddr);
                                    List <byte> answer;
                                    byte bytesCount;
                                    string childName;
                                    ModbusItem modbusitem;
                                    ModbusHoldingRegister modbusHr;
                                    byte[] msg;
                                    switch (funcCode)
                                    {
                                    case 3:     // - read holding registers
                                    case 4:     // - read input registers
                                        answer = new List <byte>();
                                        answer.AddRange(BitConverter.GetBytes(Swap(header1)));
                                        answer.AddRange(BitConverter.GetBytes(Swap(header2)));
                                        bytesCount = Convert.ToByte(regCount * 2);
                                        packetLen  = Convert.ToUInt16(bytesCount + 3);    //
                                        answer.AddRange(BitConverter.GetBytes(Swap(packetLen)));
                                        answer.Add(nodeAddr);
                                        answer.Add(funcCode);
                                        answer.Add(bytesCount);
                                        for (var addr = 0; addr < regCount; addr++)
                                        {
                                            if (funcCode == 3)
                                            {
                                                EnsureModbusHR(nodeAddr, startAddr + addr);
                                            }
                                            else
                                            {
                                                EnsureModbusAI(nodeAddr, startAddr + addr);
                                            }
                                            childName = funcCode == 3 ? $"Node{nodeAddr}.HR{startAddr + addr}" : $"Node{nodeAddr}.AI{startAddr + addr}";
                                            while (!DictModbusItems.TryGetValue(childName, out modbusitem))
                                            {
                                                Thread.Sleep(10);
                                            }
                                            ushort value;
                                            if (funcCode == 3)
                                            {
                                                modbusHr = (ModbusHoldingRegister)modbusitem;
                                                value    = BitConverter.ToUInt16(BitConverter.GetBytes(modbusHr.IntValue), 0);
                                            }
                                            else
                                            {
                                                var modbusAi = (ModbusAnalogInput)modbusitem;
                                                value        = BitConverter.ToUInt16(BitConverter.GetBytes(modbusAi.IntValue), 0);
                                            }
                                            answer.AddRange(BitConverter.GetBytes(Swap(value)));
                                        }
                                        list.Clear();
                                        list.AddRange(answer.Select(t => string.Format("{0}", t)));
                                        //Say("A:" + string.Join(",", list));
                                        msg = answer.ToArray();
                                        stream.Write(msg, 0, msg.Length);
                                        break;

                                    case 6:     // write one register
                                        answer = new List <byte>();
                                        answer.AddRange(BitConverter.GetBytes(Swap(header1)));
                                        answer.AddRange(BitConverter.GetBytes(Swap(header2)));
                                        bytesCount = Convert.ToByte(regCount * 2);
                                        packetLen  = Convert.ToUInt16(bytesCount + 3);    //
                                        answer.AddRange(BitConverter.GetBytes(Swap(packetLen)));
                                        answer.Add(nodeAddr);
                                        answer.Add(funcCode);
                                        answer.AddRange(BitConverter.GetBytes(Swap(startAddr)));
                                        answer.AddRange(BitConverter.GetBytes(Swap(singleValue)));
                                        EnsureModbusHR(nodeAddr, startAddr);
                                        childName = $"Node{nodeAddr}.HR{startAddr}";
                                        while (!DictModbusItems.TryGetValue(childName, out modbusitem))
                                        {
                                            Thread.Sleep(10);
                                        }
                                        modbusHr          = (ModbusHoldingRegister)modbusitem;
                                        modbusHr.IntValue = BitConverter.ToInt16(BitConverter.GetBytes(singleValue), 0);
                                        while (!DictModbusItems.TryUpdate(childName, modbusHr, modbusHr))
                                        {
                                            Thread.Sleep(10);
                                        }
                                        locEvClient.UpdateProperty("fetching", $"Node:{nodeAddr}:{funcCode}", $"HR:{startAddr}", $"{modbusHr.IntValue}", false);
                                        list.Clear();
                                        list.AddRange(answer.Select(t => string.Format("{0}", t)));
                                        //Say("A:" + string.Join(",", list));
                                        msg = answer.ToArray();
                                        stream.Write(msg, 0, msg.Length);
                                        break;

                                    case 16:     // write several registers
                                        answer = new List <byte>();
                                        answer.AddRange(BitConverter.GetBytes(Swap(header1)));
                                        answer.AddRange(BitConverter.GetBytes(Swap(header2)));
                                        answer.AddRange(BitConverter.GetBytes(Swap(6)));
                                        answer.Add(nodeAddr);
                                        answer.Add(funcCode);
                                        answer.AddRange(BitConverter.GetBytes(Swap(startAddr)));
                                        answer.AddRange(BitConverter.GetBytes(Swap(regCount)));
                                        var bytesToWrite = bytes[12];
                                        if (bytesToWrite != regCount * 2)
                                        {
                                            break;
                                        }
                                        var n = 13;
                                        for (var i = 0; i < regCount; i++)
                                        {
                                            var value = Convert.ToUInt16(bytes[n] * 256 + bytes[n + 1]);
                                            EnsureModbusHR(nodeAddr, startAddr + i);
                                            childName = $"Node{nodeAddr}.HR{startAddr + i}";
                                            while (!DictModbusItems.TryGetValue(childName, out modbusitem))
                                            {
                                                Thread.Sleep(10);
                                            }
                                            modbusHr          = (ModbusHoldingRegister)modbusitem;
                                            modbusHr.IntValue = BitConverter.ToInt16(BitConverter.GetBytes(value), 0);
                                            while (!DictModbusItems.TryUpdate(childName, modbusHr, modbusHr))
                                            {
                                                Thread.Sleep(10);
                                            }
                                            locEvClient.UpdateProperty("fetching", $"Node:{nodeAddr}:{funcCode}", $"HR:{startAddr + i}", $"{modbusHr.IntValue}", false);
                                            n = n + 2;
                                        }
                                        list.Clear();
                                        list.AddRange(answer.Select(t => string.Format("{0}", t)));
                                        //Say("A:" + string.Join(",", list));
                                        msg = answer.ToArray();
                                        stream.Write(msg, 0, msg.Length);
                                        break;
                                    }
                                }
                                // Shutdown and end connection
                                clientData.Close();
                            }
                            catch (Exception ex)
                            {
                                if (!worker.CancellationPending)
                                {
                                    Say(worker, ex.Message);
                                }
                            }
                        });
                    }
                    catch (SocketException exception)
                    {
                        if (!worker.CancellationPending)
                        {
                            Say(worker, $"Ошибка приёма: {exception.Message}");
                        }
                        break;
                    }
                } while (!worker.CancellationPending);
                listener.Stop();
                Say(worker, $"\nСокет TCP({tt.Port}) - остановка прослушивания.");
            }

            #endregion работа с Tcp портом
        }