Драйвер в режиме TcpServer

Просмотр 15 сообщений - с 1 по 15 (из 15 всего)
  • Автор
    Сообщения
  • #38406
    JurasskPark
    Участник

    Михаил, подскажите, если канал в режиме TcpServer
    Behavior = Slave
    ClientLifetime = 3600
    ConnectionMode = Shared
    DeviceMapping = ByIPAddress
    TcpPort = 5008
    То как в драйвере через TcpServer получать данные?
    Я попробовал так

    
    
            /// <summary>
            /// Performs a communication session.
            /// </summary>
            public override void Session()
            {
                base.Session();
                Stopwatch stopwatch = Stopwatch.StartNew();
    
                string hex = string.Empty;
                string logText = string.Empty;
    
                if (project.SystemSettings.AsClient)
                {
    
                }
                else if (project.SystemSettings.AsServer)
                {
                    int countConnection = Connection.Read(bufferReceiver, offset, count, timeout, format, out logText);
                    hex = Hex.StringX16.ToStringFormatDot(bufferReceiver);
                }
    
                stopwatch.Stop();
                Log.WriteLine(Locale.IsRussian ?
                    "Получено за {0} мс" :
                    "Received in {0} ms", stopwatch.ElapsedMilliseconds);
    
                LogDriver(hex);
                LogDriver(logText);
    
                FinishRequest();
                FinishSession();
            }
    
    #38407
    JurasskPark
    Участник

    Коммуникатор пишет «Ошибка при создании линии связи [1801] METRO-Server: Поведение Slave канала связи не поддерживается устройством [18000] Server.»

    А как это поведение поддержать в режиме Slave?)
    Какие условие нужно выполнить?

    #38408
    JurasskPark
    Участник
    
            /// <summary>
            /// Checks that all devices on the communication line support the channel behavior.
            /// </summary>
            protected void CheckBehaviorSupport()
            {
                HashSet<string> deviceTypeNames = new HashSet<string>();
    
                foreach (DeviceLogic deviceLogic in LineContext.SelectDevices())
                {
                    deviceTypeNames.Add(deviceLogic.GetType().FullName);
    
                    if (!deviceLogic.CheckBehaviorSupport(Behavior))
                    {
                        throw new ScadaException(Locale.IsRussian ?
                            "Поведение {0} канала связи не поддерживается устройством {1}." :
                            "{0} behavior of the communication channel is not supported by the device {1}",
                            Behavior, deviceLogic.Title);
                    }
                }
    
                if (Behavior == ChannelBehavior.Slave && deviceTypeNames.Count > 1)
                {
                    Log.WriteWarning(Locale.IsRussian ?
                        "Не рекомендуется использовать устройства разных типов на одной линии связи" :
                        "It is not recommended to use devices of different types on the same communication line");
                }
            }
    

    То есть драйвер не прошел проверку deviceLogic.CheckBehaviorSupport(Behavior)…
    Значит нужно указать… Но как и где… )

    #38409
    Mikhail
    Модератор

    В режиме Slave нужно вместо метода Session использовать методы ReceiveIncomingRequest и ProcessIncomingRequest.

    Примеры из DrvModbusSlave

            public override void ReceiveIncomingRequest(Connection conn, IncomingRequestArgs requestArgs)
            {
                if (fatalError)
                {
                    requestArgs.NextDevice = true;
                }
                else
                {
                    base.ReceiveIncomingRequest(conn, requestArgs);
    
                    if (receiveRequest(conn, out ModbusRequest request))
                        ProcessRequest(conn, request, requestArgs);
                    else
                        requestArgs.HasError = true;
                }
            }
    
            public override void ProcessIncomingRequest(byte[] buffer, int offset, int count,
                IncomingRequestArgs requestArgs)
            {
                if (fatalError)
                {
                    requestArgs.NextDevice = true;
                }
                else
                {
                    base.ProcessIncomingRequest(buffer, offset, count, requestArgs);
    
                    if (parseRequest(buffer, offset, count, out ModbusRequest request))
                        ProcessRequest(Connection, request, requestArgs);
                    else
                        requestArgs.HasError = true;
                }
            }
    
            public override bool CheckBehaviorSupport(ChannelBehavior behavior)
            {
                return behavior == ChannelBehavior.Slave;
            }
    
    #38410
    Mikhail
    Модератор

    В Session() можно, например, устанавливать недостоверность данных, если они давно не приходили.

    #38411
    JurasskPark
    Участник

    Спасибо! Буду пробовать!

    #38412
    JurasskPark
    Участник

    Заработало!

    Вот этого мне счастья не хватало! 🙂

    
           public override bool CheckBehaviorSupport(ChannelBehavior behavior)
            {
                return behavior == ChannelBehavior.Slave;
            }
    
    #38413
    JurasskPark
    Участник

    Вопрос номер 2.
    public override void ReceiveIncomingRequest(Connection conn, IncomingRequestArgs requestArgs) — вызывается и всё что там есть — я вижу.

    public override void ProcessIncomingRequest(byte[] buffer, int offset, int count, IncomingRequestArgs requestArgs) — не вызывается. Что я делаю не так?

    При этом я в логе вижу, постоянные попытки подключиться.

    #38417
    Mikhail
    Модератор

    Вариант ReceiveIncomingRequest вызывается в зависимости от типа канала связи. Попробуйте канал UDP — скорее всего вызовется другой вариант метода.
    Один из них вызывается, когда уже пришли и считаны все данные, а другой когда данные пришли, но ещё не считаны.

    #38419
    JurasskPark
    Участник

    При UDP пишет ошибку

    2025-05-20 13:38:32 Сеанс связи с устройством [18000] Server
    2025-05-20 13:38:32 Ошибка при вызове метода Session устройства [18000] Server:
    Scada.ScadaException: Ошибка при считывании данных: An invalid IP address was specified.
    —> System.FormatException: An invalid IP address was specified.
    —> System.Net.Sockets.SocketException (10022): Получен недопустимый аргумент.
    — End of inner exception stack trace —
    at System.Net.IPAddressParser.Parse(ReadOnlySpan`1 ipSpan, Boolean tryParse)
    at System.Net.IPAddress.Parse(String ipString)
    at Scada.Comm.Drivers.DrvCnlBasic.Logic.UdpConnection.CreateRemoteEndPoint()
    at Scada.Comm.Drivers.DrvCnlBasic.Logic.UdpConnection.Read(Byte[] buffer, Int32 offset, Int32 count, Int32 timeout, ProtocolFormat format, String& logText)
    — End of inner exception stack trace —
    at Scada.Comm.Drivers.DrvCnlBasic.Logic.UdpConnection.Read(Byte[] buffer, Int32 offset, Int32 count, Int32 timeout, ProtocolFormat format, String& logText)
    at Scada.Comm.Drivers.DrvHSMSLogic.Logic.DevHSMSLogic.Session()
    at Scada.Comm.Engine.DeviceWrapper.Session()

    #38420
    JurasskPark
    Участник

    Смерил тип TCP-сервер на общий

    2025-05-20 13:42:50 Приём входящего запроса от 10.50.*.*
    2025-05-20 13:42:50 Ошибка при вызове метода Session устройства [18000] Server:
    Scada.ScadaException: Ошибка при считывании данных: Timeout can be only be set to ‘System.Threading.Timeout.Infinite’ or a value > 0. (Parameter ‘value’)
    —> System.ArgumentOutOfRangeException: Timeout can be only be set to ‘System.Threading.Timeout.Infinite’ or a value > 0. (Parameter ‘value’)
    at System.Net.Sockets.NetworkStream.set_ReadTimeout(Int32 value)
    at Scada.Comm.Drivers.DrvCnlBasic.Logic.TcpConnection.Read(Byte[] buffer, Int32 offset, Int32 count, Int32 timeout, ProtocolFormat format, String& logText)
    — End of inner exception stack trace —
    at Scada.Comm.Drivers.DrvCnlBasic.Logic.TcpConnection.Read(Byte[] buffer, Int32 offset, Int32 count, Int32 timeout, ProtocolFormat format, String& logText)
    at Scada.Comm.Drivers.DrvHSMSLogic.Logic.DevHSMSLogic.Session()
    at Scada.Comm.Engine.DeviceWrapper.Session()

    #38421
    manjey73
    Участник

    Timeout в настройках 0? это поле не считываешь и не указываешь явно ?

    #38423
    JurasskPark
    Участник

    >>а другой когда данные пришли, но ещё не считаны.
    Короче, хотите обижайтесь, хотите баньте, но я через дебаггер посмотрел исходных код ModbusSlave, и посмотрел там как происходит.

    
     /// <summary>
     /// Receives an unread incoming request in slave mode.
     /// </summary>
     public override void ReceiveIncomingRequest(Connection conn, IncomingRequestArgs requestArgs)
     {
         Log.WriteLine();
    
         if (string.IsNullOrEmpty(conn.RemoteAddress))
         {
             Log.WriteAction(Locale.IsRussian ?
                 "Приём входящего запроса" :
                 "Receive incoming request");
         }
         else
         {
             Log.WriteAction(Locale.IsRussian ?
                 "Приём входящего запроса от {0}" :
                 "Receive incoming request from {0}", conn.RemoteAddress);
         }
    
         string logText = string.Empty;
         bool a = ReadDataConnection(conn, out logText);
    }
    
    public bool ReadDataConnection(Connection connection, out string logText)
    {
        //bool result = false;
        string text = string.Empty;
        int num = connection.Read(this.buffer, 0, 1000, ((DeviceLogic)this).PollingOptions.Timeout, ProtocolFormat.Hex, out logText);
    
        Log.WriteAction(@$"Num = {num}");
        Log.WriteAction(@$"Buffer = " + Hex.StringX16.ToStringFormatDot(buffer));
        Log.WriteAction(@$"Offset = {0}");
        Log.WriteAction(@$"Count = {1000}");
        Log.WriteAction(@$"Timeout = {((DeviceLogic)this).PollingOptions.Timeout}");
        Log.WriteAction(@$"Protocol = {ProtocolFormat.Hex}");
        Log.WriteAction(@$"Log Text = {logText}");
    
        return true;
    }
    

    Вот так работает.

    #38424
    JurasskPark
    Участник

    То есть действительно, нужно было после появление коннекта делать обращение на чтение данных.
    Непривычно просто. 🙂

    #38425
    JurasskPark
    Участник

    А. И еще в драйвере нужно было выставить ((DeviceLogic)this).ConnectionectionRequired = false;

Просмотр 15 сообщений - с 1 по 15 (из 15 всего)
  • Вы должны авторизироваться для ответа в этой теме.