powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / класс serialport и синхронизация потоков
9 сообщений из 9, страница 1 из 1
класс serialport и синхронизация потоков
    #39331140
kadet635
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Здраствуйте, нужен совет, как грамотно синхронизировать потоки в C#, точнее синхронизировать доступ к serialport.
Есть некое приложение которое работает со СКУД через com порт.
В функции ReadEvent организовано считывание событий в бесконечном цикле
При возникновении события в контроллеры записываются ключи через serialport, как синхронизировать потоки чтоб в ком порт отправлять правильные данные

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
325.
326.
327.
328.
329.
330.
331.
332.
333.
334.
335.
336.
337.
338.
339.
340.
341.
342.
343.
344.
345.
346.
347.
348.
349.
350.
351.
352.
353.
354.
355.
356.
357.
358.
359.
360.
361.
362.
363.
364.
365.
366.
367.
368.
369.
370.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;
using FirebirdSql.Data.FirebirdClient;
using System.Collections;
using System.Threading;
using System.Runtime.Remoting.Contexts;


namespace GateConsole
{
    class Program
    {       
        static FbConnection connection;
        static Mutex mutexObj = new Mutex();
        static void Main(string[] args)
        {           
            List<Contr> ContrList = new List<Contr>();
            FbConnectionStringBuilder cs = new FbConnectionStringBuilder();
            
            cs.DataSource = "192.168.0.220";
            cs.Database = "FITNESS";
            cs.UserID = "SYSDBA";
            cs.Password = "metalink";
            cs.Charset = "NONE";
            cs.Pooling = false;
            connection = new FbConnection(cs.ToString());
            GatePort.InitializationPort();
            GatePort._serialPort.Open();
            connection.Open();
            ///////////////////////////////////////////////////////////////////
            FbRemoteEvent revent = new FbRemoteEvent(connection);
            revent.AddEvents(new string[] { "EDIT_GATEKEY"/*, "NEW_EVENT", "new_visit"*/ });
            //Добавить функцию обратного вызова для Firebird событий
            revent.RemoteEventCounts += new FbRemoteEventEventHandler(WriteKey);
            revent.QueueEvents();
            ////////////////////////////////////////////////////////////////////            
            FbCommand com = new FbCommand("select contrid,addr from contr", connection);
            FbDataReader reader = com.ExecuteReader();
            if (reader.HasRows)
            {
                while (reader.Read())
                {
                    ContrList.Add(new Contr(Convert.ToInt32(reader.GetValue(0)), Convert.ToByte(reader.GetValue(1))));
                }
            }
            ReadEvent(ContrList);
            Console.WriteLine("Достигнута конечная точка программы");     
            Console.ReadLine(); 
            connection.Close();
            GatePort._serialPort.Close();
           
        }

      
        static void WriteKey(object sender, FbRemoteEventEventArgs args)
        {
            List<Key> ListKey = new List<Key>();
            byte[] dataRead;
            //Console.WriteLine("Предъмьютекс");
            try
            {
                //получить ключи и контроллеры
                //записать их в конроллеры
                FbCommand com = new FbCommand("select * from eventbufer", connection);
                FbDataReader reader = com.ExecuteReader();
                if (reader.HasRows)
                {
                    while (reader.Read())
                    {
                        ListKey.Add(new Key()
                        {
                            KeyId = (int)reader.GetValue(0),
                            AddresContr = (int)reader.GetValue(1),
                            AddresKey = (int)reader.GetValue(2),
                            KeySeries = (int)reader.GetValue(3),
                            KeyNumber = (int)reader.GetValue(4)
                        });
                    }

                    foreach (var i in ListKey)
                    {
                        Console.WriteLine("Контроллер {0} карта {1},{2}", i.AddresContr, i.KeySeries, i.KeyNumber);
                        dataRead = i.WriteKey(0x01);//Запись ключа в банк 1

                        dataRead = i.WriteKey(0x02);//Запись ключа в банк 2
                        
                        com = new FbCommand("delete  from eventbufer where id=" + i.KeyId, connection);
                        Console.WriteLine("Удалено {0} строк", com.ExecuteNonQuery());
                    }
                };
            }
            catch (Exception ex)
            {
                Console.WriteLine("ИСКЛЮЧЕНИЕ!!! {0}", ex);
            }
           
        }

        static public string Win1251ToUTF8(string source)
        {
            var fromEncodind = Encoding.GetEncoding("Windows-1251");//из какой кодировки
            var bytes = fromEncodind.GetBytes(source);
            var toEncoding = Encoding.UTF8;//в какую кодировку
            source = toEncoding.GetString(bytes);
            return source;
        }

        static void ReadEvent(Object controller)
        {
            List<Contr> ContrList = (List<Contr>)controller;
            int PointerUp = 0;
            int PointerDown = 0;
            List<ValueEvent> EventContr = new List<ValueEvent>();
            FbCommand com = new FbCommand("select * from eventscode", connection);
            FbDataReader reader = com.ExecuteReader();
            if (reader.HasRows)
            {
                while (reader.Read())
                {
                    EventContr.Add(new ValueEvent((int)reader.GetValue(0), Win1251ToUTF8((string)reader.GetValue(1))));
                }
            }
      
            byte[] dataRead, data;
            dataRead = new byte[] { 0x00 };

            while (true)
            {
                
                foreach (var cont in ContrList)
                {                   
                    dataRead = GatePort.RequestContr(0x09, cont.AdressContr, new byte[] { });//Номер версии контроллера                   
                    cont.VersionNumber = dataRead[6] >> 4;
                    //Console.WriteLine("Номер Версии:{0}", dataRead[6] >> 4);
                    switch (cont.VersionNumber)
                    {
                        //GATE-4 (адреса 0-7FFFh)
                        //GATE-8000 (адреса 0-FFFFh).
                        case 8:
                            cont.MaxAddrByte = 65535;
                            break;
                        case 4:
                            cont.MaxAddrByte = 32767;
                            break;
                    }

                    do
                    {
                        System.Threading.Thread.Sleep(100);
                       
                        dataRead = GatePort.RequestContr(0x04,cont.AdressContr, new byte[] { 0x00, 0xD0, 0x04, 0x00, 0x08, });//Нижняя и верхняя границы
                       
                        //Console.WriteLine("\nПоложение указателей");
                        //foreach (var i in dataRead)
                        //{
                        //    Console.Write(Convert.ToString(i, 16) + " ");
                        //}
                        Array.Reverse(dataRead);
                        PointerUp = BitConverter.ToInt16(dataRead, 4);
                        PointerDown = BitConverter.ToInt16(dataRead, 2);
                        Console.ForegroundColor = ConsoleColor.Green;
                        Console.WriteLine("\nАдрес нижней границы:{0}, адрес верхней границы: {1}", PointerDown, PointerUp);
                        Console.ResetColor();

                        if (PointerDown != PointerUp)
                        {
                            byte[] BufByte = BitConverter.GetBytes(PointerDown);//убрал+8, 2 байта-нижняя граница                            
                            dataRead = GatePort.RequestContr(0x04, cont.AdressContr, new byte[] { 0x02, 0xA0, 0x08, BufByte[1], BufByte[0] });
                            Console.WriteLine("Ответ сервера с событием");
                            foreach (var i in dataRead)
                            {
                                Console.Write(Convert.ToString(i, 16) + " ");
                            }
                            Console.WriteLine("\nНовое событие события:{0}, сдвиг на 1 разряд:{1}", dataRead[6], (dataRead[6] & 127));

                            foreach (ValueEvent i in EventContr)
                            {
                                if (i.ValueEventId == (dataRead[6] & 127))
                                {
                                    Console.ForegroundColor = ConsoleColor.Red;
                                    Console.WriteLine("Контроллер {5} Наименование события {0}, Месяц:{1:X}, Дата: {2:X}, Часы: {3:X}, Минуты:{4:X}", i.Name.ToString(), (int)dataRead[9], (int)dataRead[10], (int)dataRead[11], (int)dataRead[12],cont.AdressContr);
                                    Console.ResetColor();
                                    string date = String.Format("{0:X}.{1:X}.{2}", (int)dataRead[10], (int)dataRead[9],DateTime.Now.Year);
                                    string time = String.Format("{0:X}:{1:X}:{2:X}", (int)dataRead[11], (int)dataRead[12],(int)dataRead[13]);
                                    com = new FbCommand("insert into events (rearerid,eventscode,ddate,ttime,ser,number,contrid,client) values (" + cont.ContrId + "," + (dataRead[6] & 127) + "," + date + "," + time + "," + null+","+null+","+cont.ContrId+")", connection);
                                
                                }
                            }

                            //увелчить на 8 нижнюю границу  
                            if ((PointerDown + 8) >= cont.MaxAddrByte)
                            { PointerDown = -8; }
                            byte[] data11 = BitConverter.GetBytes(PointerDown + 8);                        
                            dataRead = GatePort.RequestContr(0x05, cont.AdressContr, new byte[] { 0x00, 0xD0, 0x02, 0x00, 0x0A, data11[1], data11[0] });
                            Console.WriteLine("Ответ после изменения нижней границы");
                            foreach (var i in dataRead)
                            {
                                Console.Write(Convert.ToString(i, 16) + " ");
                            }
                        }
                    } while (PointerDown != PointerUp);
                    Console.ForegroundColor = ConsoleColor.DarkBlue;
                    Console.WriteLine("Все события контроллера {0} считаны, переход к следующемуу контроллеру", cont.AdressContr);
                    Console.ResetColor();
                    System.Threading.Thread.Sleep(100);
                }
            }
        }
    }

        class Key
        {
            public int KeyId { get; set; }
            public int KeySeries { get; set; }
            public int KeyNumber { get; set; }
            public int AddresKey { get; set; }
            public int AddresContr { get; set; }

            public byte[] WriteKey(byte bank)
            {
                byte[] buf = BitConverter.GetBytes(AddresKey);
                byte[] BufKeyNumber = BitConverter.GetBytes(KeyNumber);
                byte[] Request = GatePort.RequestContr(0x05, (byte)AddresContr, new byte[] { bank, 0xA0, 0x08, buf[1], buf[0],
                    0x00,
                    0x00,
                    0x00,
                    (byte)KeySeries,
                    BufKeyNumber[1],
                    BufKeyNumber[0],
                    0x00,
                    0x80,//16 байт
                });               
                return Request;
            }
    }

        class Contr
        {
            public int ContrId { get; set; }
            public byte AdressContr { get; set; }
            public string ContrName { get; set; }
            public int VersionNumber { get; set; }
            public int MaxAddrByte { get; set; }//максимальный адрес буфера событий
            //IEnumerable<Key> Keys { get; set; }

            public Contr(int contrid, byte adres)
            {
                ContrId = contrid;
                AdressContr = adres;
            }         
        }


        class ValueEvent
        {
            public int ValueEventId { get; set; }
            public string Name { get; set; }
            public ValueEvent(int id, string name)
            {
                ValueEventId = id;
                Name = name;
            }

        }

    static class GatePort
    {
        public static SerialPort _serialPort;
        public static byte[] Data, DataRead;
        static byte ContrSumma;
        static int ErrorCount;

        public static void InitializationPort()
        {
            _serialPort = new SerialPort("COM4", 19200, Parity.None, 8, StopBits.One);
            _serialPort.Handshake = Handshake.None;
            _serialPort.ReadTimeout = 1500;
        }

        public static byte[] RequestContr(byte CodeRead, byte AddressContr, byte[] BodyCommand)
        {
            ErrorCount = 0;
            ContrSumma = CodeRead;
            Data = new byte[] { 0xFA, 0x01, AddressContr, CodeRead };
            //Сначала обработать bodycommand на предмет наличия FF,F5
            foreach (var i in BodyCommand)
            {
                Array.Resize(ref Data, Data.Length + CheckByte(i).Length);
                CheckByte(i).CopyTo(Data, Data.Length - CheckByte(i).Length);
            }
            for (int i = 4; i < Data.Length; i++)
            {
                ContrSumma = (byte)(ContrSumma ^ Data[i]);
            }
           // ContrSumma = 0xF5;
            switch (CheckByte(ContrSumma).Length)
            {
                case 1:
                    Array.Resize(ref Data, Data.Length + 2);
                    Data[Data.Length - 2] = ContrSumma;
                    Data[Data.Length - 1] = 0xF5;
                    break;
                case 2:
                    Array.Resize(ref Data, Data.Length + 3);
                    Data[Data.Length - 3] = CheckByte(ContrSumma)[0];
                    Data[Data.Length - 2] = CheckByte(ContrSumma)[1];
                    Data[Data.Length - 1] = 0xF5;
                    break;
            }
            //Console.WriteLine("Запрос на сервер:");
            //foreach(var i in Data)
            //{
            //    Console.Write("{0} ",i);
            //}
            do
            {
                try
                {
                    _serialPort.Write(Data, 0, Data.Length);
                    System.Threading.Thread.Sleep(100);
                    DataRead = new byte[255];
                    int KollByte = _serialPort.Read(DataRead, 0, DataRead.Length);
                    Array.Resize(ref DataRead, KollByte);
                    ErrorCount = 0;
                }
                catch (TimeoutException)
                {
                    ErrorCount++;
                    if (ErrorCount >= 10)
                    { ErrorCount = 0; }
                    Console.WriteLine("Контроллер не ответил");
                }
            } while (ErrorCount != 0);
            return DataRead;
            //Console.WriteLine("Результат:");
            //foreach (var i in DataRead)
            //{
            //    Console.Write("{0} ", i);
            //}

        }


        static byte[] CheckByte(byte b)
        {
            byte[] buf;
            switch (b)
            {
                case 0xFA:
                    buf = new byte[] { 0xFF, 0x01 };
                    break;
                case 0xF5:
                    buf = new byte[] { 0xFF, 0x02 };
                    break;

                case 0xFF:
                    buf = new byte[] { 0xFF, 0x03 };
                    break;
                default:
                    buf = new byte[] { b };
                    break;
            }
            return buf;
        }
    }
}
...
Рейтинг: 0 / 0
класс serialport и синхронизация потоков
    #39331142
kadet635
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Эта дублилированная тема, слчайно добавил, не знаю как удалить
...
Рейтинг: 0 / 0
класс serialport и синхронизация потоков
    #39331240
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kadet635Эта дублилированная тема, слчайно добавил, не знаю как удалить
3аголовки ра3ные O_o
может у вас кратковременные потери памяти или ра3двоение личности? :))
...
Рейтинг: 0 / 0
класс serialport и синхронизация потоков
    #39331245
Pallaris
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Портянку такую разгребать желания нет. Общий принцип работы с ком-портом такой - посылаешь пакет, и пока не получил ответ или не истек разумный таймаут, ничего слать нельзя
...
Рейтинг: 0 / 0
класс serialport и синхронизация потоков
    #39331251
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
исполь3уйте асинхронность, так как это будет блокировать UI, а время ответа или не ответа могут быть очень большими.
...
Рейтинг: 0 / 0
класс serialport и синхронизация потоков
    #39331356
Фотография fortibransa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
PallarisПортянку такую разгребать желания нет. Общий принцип работы с ком-портом такой - посылаешь пакет, и пока не получил ответ или не истек разумный таймаут, ничего слать нельзяМожно, но может возникнуть гемор, но может и не возникнуть.
...
Рейтинг: 0 / 0
класс serialport и синхронизация потоков
    #39331369
yura-007
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kadet635,
Ты хочешь одновременно из нескольких потоков работать с несколькими контроллерами через ком порт, что бы уменьшить время итераций в бесконечном цикле и тем самым повысить производительность? Описание протокола есть? Если долгое время не опрашивать контроллеры, выключить программу например, затем запустить, время опроса одного контроллера увеличится, т.к. программа вычитывает накопившиеся данные или все работает иначе? Что за контроллеры?
...
Рейтинг: 0 / 0
класс serialport и синхронизация потоков
    #39331432
yura-007
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kadet635,
Pallaris все правильно сказал на счет принципа работы. Контроллеры могут поддерживать несколько протоколов работающих по одному интерфейсу, например контроллер Carel pco3 поддерживает модбас и свой закрытый протокол carel, в зависимости от задачи, количества контроллеров в сети, программах в контроллерах(особенно если они свободно программируемые) дабы повысить производительность, выбирается тот или иной протокол. Разница в том, что протокол Carel вычитывает все накопившиеся изменения с момента последнего опроса, поэтому если часто меняющихся параметров много и все они не важны, то есть протокол модбас, с помощью которого ты сам определяешь когда какие регистры читать.
Твоя программа может в разных потоках выполнять какие-то обработки, но общение с ком портом будет происходить скорей всего в одном потоке. Учитывая что у тебя консольное приложение, с потоками можно сильно не заморачиваться.
...
Рейтинг: 0 / 0
класс serialport и синхронизация потоков
    #39331957
Фотография Cat2
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
fortibransaPallarisПортянку такую разгребать желания нет. Общий принцип работы с ком-портом такой - посылаешь пакет, и пока не получил ответ или не истек разумный таймаут, ничего слать нельзяМожно, но может возникнуть гемор, но может и не возникнуть.
Программирование - всегда компромисс между желаниями и возможностями
...
Рейтинг: 0 / 0
9 сообщений из 9, страница 1 из 1
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / класс serialport и синхронизация потоков
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]