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

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

    Еще бы понять логику вашего действия:

    
    	public override void ReceiveIncomingRequest(Connection conn, IncomingRequestArgs requestArgs)
    	{
    		if (f)
    		{
    			requestArgs.NextDevice = true;
    			return;
    		}
    		((DeviceLogic)this).ReceiveIncomingRequest(conn, requestArgs);
    		if (i(conn, out var A_))
    		{
    			a(conn, A_, requestArgs);
    		}
    		else
    		{
    			requestArgs.HasError = true;
    		}
    	}
    

    Можно оригинал и описание?

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

    Это откуда взято?

    #40808
    JurasskPark
    Участник

    Slave Modbus driver…

    #40824
    Mikhail
    Модератор
    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;
        }
    }
    #40825
    Mikhail
    Модератор

    ModbusSlave сложнее, чем обычный драйвер, потому что формат данных разный для RTU и TCP.

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

    При использовании TCP будет вызываться только ReceiveIncomingRequest, насколько я помню.
    ProcessIncomingRequest вызывается для канала UDP.

    #40836
    JurasskPark
    Участник

    ModbusSlave сложнее, чем обычный драйвер, потому что формат данных разный для RTU и TCP

    У меня тоже два протокола заложено: SECS и HSMS.

    #41268
    JurasskPark
    Участник

    Можете меня наконец-то поздравить. Я разобрался, как работает
    BinStopCondition stopCond.

    Оставляю здесь для себя.

    
    BinStopCondition stopCond = new ClientStopCondition(device.TypeProtocol);
    int count = connection.Read(this.buffer, 0, this.buffer.Length, ((DeviceLogic)this).PollingOptions.Timeout, stopCond, out bool stopReceived, ProtocolFormat.Hex, out logText);
    
    
    using DebugerLog;
    using Scada.Comm.Channels;
    
    public class ClientStopCondition : BinStopCondition
    {
        private int _bytesRead = 0;
        private int _expectedLength = -1;
        private readonly NetCoreSECS.Protocol _protocol;
        private bool _isLengthDetermined = false;
    
        public ClientStopCondition(NetCoreSECS.Protocol protocol) : base(0)
        {
            _protocol = protocol;
            StopSeq = null;
            Debuger.Log($"Создан ClientStopCondition для протокола: {_protocol}");
        }
    
        public override bool CheckCondition(byte[] buffer, int index)
        {
            _bytesRead++;
    
            // Для HSMS: определяем длину после 4 байт
            if (_protocol == NetCoreSECS.Protocol.HSMS && !_isLengthDetermined && _bytesRead >= 4)
            {
                // Читаем длину ДАННЫХ из первых 4 байт
                int dataLength = (buffer[0] << 24) |
                                 (buffer[1] << 16) |
                                 (buffer[2] << 8) |
                                 buffer[3];
    
                // Общая длина = 4 байта длины + длина данных
                _expectedLength = 4 + dataLength;
                _isLengthDetermined = true;
    
                Debuger.Log($"✓ HSMS: Длина данных = {dataLength}, Общая длина = {_expectedLength} байт");
            }
            // Для SECS: определяем длину после 1 байта
            else if (_protocol == NetCoreSECS.Protocol.SECS && !_isLengthDetermined && _bytesRead >= 1)
            {
                // SECS: первый байт = длина данных
                int dataLength = buffer[0];
                _expectedLength = 1 + dataLength + 2; // Длина + данные + CRC
                _isLengthDetermined = true;
    
                Debuger.Log($"✓ SECS: Длина данных = {dataLength}, Общая длина = {_expectedLength} байт");
            }
    
            // Проверяем условие остановки
            bool shouldStop = _isLengthDetermined && _bytesRead >= _expectedLength;
    
            if (shouldStop)
            {
                Debuger.Log($"✅ Прочитан полный пакет: {_bytesRead} байт");
            }
    
            return shouldStop;
        }
    
        public void Reset()
        {
            _bytesRead = 0;
            _expectedLength = -1;
            _isLengthDetermined = false;
        }
    }
    
    #41269
    manjey73
    Участник

    дык спросил бы, я давно пользуюсь 🙂
    со времен когда Михаила попросил добавить остановку по массив(АМ) байт, а не по одному байту или одному массиву.

    #42150
    JurasskPark
    Участник
    
    if (deviceLogic.NumAddress != request.UnitID)
        LineContext.GetDeviceByAddress(request.UnitID, out deviceLogic)
    

    Для информации.
    Я попался на LineContext.GetDeviceByAddress.

    LineContext.GetDeviceByAddress — если int передать, то это поиск по адресу устройства.
    LineContext.GetDeviceByAddress — если передать string, то это поиск по ip.

    А у меня стояло — LineContext.GetDevice — это поиск по номеру устройства.

    P.S. Нашёл, когда отлаживал DrvDebug…
    Точнее везде в начале темы я пишу LineContext.GetDeviceByAddress, но потом была вспышка на солнце и в коде уже было LineContext.GetDevice. 😀

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

    Спасибо.

    #42205
    JurasskPark
    Участник

    Михаил, для закрепления темы и повторения.

    1. Приходит команда, по которой мы определяем адрес устройства.
    Библиотека понимает, что адрес устройства в полученной команде и адрес в конфигурации проекта совпадают, то мы всё равно делаем поиск через
    LineContext.GetDeviceByAddress(address, out deviceLogic)?

    if(deviceLogic.NumAddress == address)
    {
       LineContext.GetDeviceByAddress(address, out deviceLogic);
    }

    2. Приходит команда, по которой мы определяем адрес устройства.
    Библиотека понимает, что адрес устройства в полученной команде и адрес в конфигурации проекта НЕ совпадают, то мы делаем поиск через
    LineContext.GetDeviceByAddress(address, out deviceLogic)?

    if(deviceLogic.NumAddress != address)
    {
       LineContext.GetDeviceByAddress(address, out deviceLogic);
    }

    3. Приходит команда, по которой мы НЕ можем определить адрес устройства, т.к. это команда установки связи.
    Библиотека понимает, что адрес устройства в полученной команде и адрес в конфигурации проекта НЕ совпадают, но для установления связи нужно всё равно ответить.
    LineContext.GetDeviceByAddress(address, out deviceLogic) — вызывать бессмылено, устройство мы не найдем.
    Значит не вызываем?

    4. В каких случаях нужно вызывать requestArgs.TargetDevices.Add(deviceLogic)?
    Каждый раз про получении данных от устройства?
    Объясню сложность вопроса для себя.
    Если пришли данные от устройства и мы не вызвали requestArgs.TargetDevices.Add(deviceLogic), то мы не узнали, что устройство подключилось новое.
    Если мы каждый раз при получении команды, будет вызывать, то не будет ли количество TargetDevices стремится к бесконечности? Или они очищаются после каждого опроса через период времени?

    5. Нужно ли ReceiveIncomingRequest(Connection connection, IncomingRequestArgs requestArgs) завершать командами, при удачном выполнении
    LastRequestOK = true;
    FinishRequest();
    SleepPollingDelay();
    FinishSession();

    или ничего не должно быть?

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

    1-3. вроде бы так.

    4. Вызывать каждый раз, если мы нашли устройство, к которому относится запрос. Бесконечно ссылки не накопятся, потому что requestArgs существует короткое время для одного запроса.

    5. Я использую FinishRequest. Откройте код метода, посмотрите, что он делает. Он весьма короткий. FinishSession не нужен, потому что это не сеанс опроса в терминах Коммуникатора.

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

    Возможно, это уже было:

    public override void ReceiveIncomingRequest(Connection conn, IncomingRequestArgs requestArgs)
    {
        base.ReceiveIncomingRequest(conn, requestArgs);
        int readCnt = conn.Read(inBuf, 0, InBufLenght, PollingOptions.Timeout, StopCond, out bool stopReceived);
    
        if (!stopReceived)
            Log.WriteLine("Ошибка: пакет данных не обнаружен");
    
        bool procDataOK = stopReceived && ProcData(inBuf, 0, readCnt, conn, requestArgs);
        FinishRequest(requestArgs.GetFirstDevice(), procDataOK);
    }
    
    public override void ProcessIncomingRequest(byte[] buffer, int offset, int count,
        IncomingRequestArgs requestArgs)
    {
        base.ProcessIncomingRequest(buffer, offset, count, requestArgs);
        bool procDataOK = ProcData(buffer, offset, count, Connection, requestArgs);
        FinishRequest(requestArgs.GetFirstDevice(), procDataOK);
    }
    #42237
    Mikhail
    Модератор

    Из другого драйвера:

    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;
        }
    }
Просмотр 15 сообщений - с 61 по 75 (из 75 всего)
  • Для ответа в этой теме необходимо авторизоваться.