Время ожидания или Timeout

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

    В драйвере что я разрабатываю дошел до отправки и получения данных.

    
    //Отправка запроса
    Connection.Write(bufferSender, 0, bufferSender.Length, ProtocolFormat.Hex, out logText);
    //Временный буфер
    countArray = Connection.Read(tmpbufferReceiver, 0, tmpbufferReceiver.Length, channel.ReadTimeout, ProtocolFormat.Hex, out logText);
    

    Всё бы ничего, но драйвер ждет время, которое я передаю в Timeout, даже если данные давным давно пришли.
    И я всё не могу понять, как мне сделать, чтобы Timeout весь не ждал, пошел смотреть исходники.

            /// <summary>
            /// Reads data.
            /// </summary>
            public override int Read(byte[] buffer, int offset, int count, int timeout,
                ProtocolFormat format, out string logText)
            {
                try
                {
                    int readCnt = 0;
                    NetStream.ReadTimeout = timeout; // timeout is not maintained if all available data has been read
                    Stopwatch stopwatch = Stopwatch.StartNew();
    
                    while (readCnt < count && stopwatch.ElapsedMilliseconds <= timeout)
                    {
                        // read data
                        try
                        {
                            if (NetStream.DataAvailable) // checking DataAvailable is critical on Linux
                                readCnt += NetStream.Read(buffer, readCnt + offset, count - readCnt);
                        }
                        catch (IOException) { }
    
                        // accumulate data in the internal connection buffer
                        if (readCnt < count)
                            Thread.Sleep(DataAccumDelay);
                    }
    
                    logText = BuildReadLogText(buffer, offset, count, readCnt, format);
    
                    if (readCnt > 0)
                        UpdateActivityTime();
    
                    return readCnt;
                }
                catch (Exception ex)
                {
                    throw new ScadaException(CommPhrases.ReadDataError + ": " + ex.Message, ex);
                }
            }

    while (readCnt < count

    А я вот не знаю сколько мне ожидать байт в ответе. В протоколе такого нет.
    Может сделать еще одно условие, где количество ожидаемых байт не передаётся?

            public override int Read(byte[] buffer, int offset, int timeout,
                ProtocolFormat format, out string logText)
            {
                try
                {
                    int readCnt = 0;
                    NetStream.ReadTimeout = timeout; // timeout is not maintained if all available data has been read
                    Stopwatch stopwatch = Stopwatch.StartNew();
    
                    while (readCnt > 0 && stopwatch.ElapsedMilliseconds <= timeout)
                    {
                        // read data
                        try
                        {
                            if (NetStream.DataAvailable) // checking DataAvailable is critical on Linux
                                readCnt += NetStream.Read(buffer, readCnt + offset, count - readCnt);
                        }
                        catch (IOException) { }
                    }
    
                    logText = BuildReadLogText(buffer, offset, readCnt, format);
    
                    if (readCnt > 0)
                        UpdateActivityTime();
    
                    return readCnt;
                }
                catch (Exception ex)
                {
                    throw new ScadaException(CommPhrases.ReadDataError + ": " + ex.Message, ex);
                }
            }
    
    • Эта тема была изменена 2 недели назад от JurasskPark.
    • Эта тема была изменена 2 недели назад от JurasskPark.
    #27122
    JurasskPark
    Участник

    Вот что мне нужно

    
            /// <summary>
            /// Reads data.
            /// </summary>
            public override int Read(byte[] buffer, int offset, int timeout,
                ProtocolFormat format, out string logText)
            {
                try
                {
                    int readCnt = 0;
                    NetStream.ReadTimeout = timeout; // timeout is not maintained if all available data has been read
                    Stopwatch stopwatch = Stopwatch.StartNew();
    
                    while (readCnt == 0 && stopwatch.ElapsedMilliseconds <= timeout)
                    {
                        // read data
                        try
                        {
                            if (NetStream.DataAvailable) // checking DataAvailable is critical on Linux
                                readCnt += NetStream.Read(buffer, offset, buffer.Length);
                        }
                        catch (IOException) { }
                    }
    
                    logText = BuildReadLogText(buffer, offset, readCnt, format);
    
                    if (readCnt > 0)
                    {
                        Array.Resize(ref buffer, readCnt);
                        logText = BuildReadLogText(buffer, offset, readCnt, format);
                        UpdateActivityTime();
                    }
    
                    return readCnt;
                }
                catch (Exception ex)
                {
                    throw new ScadaException(CommPhrases.ReadDataError + ": " + ex.Message, ex);
                }
            }
    

    https://www.youtube.com/watch?v=MLq8Tpj_odE

    #27123
    manjey73
    Участник

    Какое у вас устройство? с последовательным портом?
    Есть идентификаторы окончания пакета?

    #27124
    manjey73
    Участник

    В драйверах есть возможность остановки по байту, по массиву байт, по массивам байт при необходимости.

    #27126
    JurasskPark
    Участник

    Какое у вас устройство? с последовательным портом?
    Есть идентификаторы окончания пакета?

    https://forum.rapidscada.ru/?topic=system-io-ports#post-27051
    Протокол ModbusRTU доработанный производителем, что там три входных параметра, но количество и адрес регистра — нету.

    #27127
    JurasskPark
    Участник

    В драйверах есть возможность остановки по байту, по массиву байт, по массивам байт при необходимости.

    А можете рассказать как для маленького ребёнка? Поподробнее. А то может и придётся Михаила дорабатывать. 🙂

    #27128
    manjey73
    Участник

    Если конец пакета можно идентифицировать, то механизм остановки по массиву байт реализован в драйверах. BinStopCondition в 5-й версии. В 6-й он немного изменился по вызову, но примерно то же самое. По крайней мере я не сильно изменял свой код.

    Могу свой пример выложить, так как тоже когда-то столкнулся с протоколом, где нет длины, но можно идентифицировать пакет по определенному массиву байт + дочитать CS или CRC

    #27129
    manjey73
    Участник

    в смысле механизм остановки реализован в ядре Scada, вы просто его реализовываете в драйвере по своему усмотрению

    #27130
    manjey73
    Участник
            private static byte[] crlf = new byte[] { 0x0D, 0x0A };
            private static byte[] drlf = new byte[] { 0x8D, 0x0A };
            private static byte[] etx = new byte[] { 0x03 };
            private static byte[] ack = new byte[] { 0x06 };
            private readonly static MyStopCondition StopCond;
            private static List<byte[]> stopList = new List<byte[]>();
    
            public class MyStopCondition : BinStopCondition // TEST логики остановки по двум или более массивам BinStopCondition
            {
                public MyStopCondition(List<byte[]> stopL)
                {
                    Stop = stopL;
                }
    
                public List<byte[]> Stop { get; private set; }
    
                public override bool CheckCondition(byte[] buffer, int index)
                {
                    foreach (var stop in Stop)
                    {
                        StopSeq = stop;
                        if (base.CheckCondition(buffer, index))
                            return true;
                    }
                    return false;
                }
            }
    
            static DevXXXXXLogic()
            {
                stopList.AddRange(new[] { drlf, crlf, etx, ack });
                StopCond = new MyStopCondition(stopList);
            }
    

    Тут сложный вымученный код, можно упростить

            /// <summary>
            /// Считать ответ из последовательного порта
            /// </summary>
            private void ReadAnswer(byte[] buffer, byte lastByte, out int readCnt, out string logText)
            {
                // считывание данных до получения массивов остановки
                bool stopReceived = false;
                bool checkWhile;
                readCnt = 0;
    
                // Чтение после 0x0D 0x0A если первый символ STX
                do
                {
                    checkWhile = false;
    
                    int readCnt1 = Connection.Read(buffer, readCnt, MaxRxDLen, PollingOptions.Timeout,
                        StopCond, out stopReceived, ProtocolFormat.String, out logText);
                    readCnt += readCnt1;
    
                    if (!prog7e1)
                    {
                        if (stopReceived && readCnt < MaxRxDLen && StopCond.StopSeq.SequenceEqual(crlf) && buffer[0] == stx)
                        {
                            checkWhile = true;
                        }
                    }
                    else
                    {
                        if (stopReceived && readCnt < MaxRxDLen && StopCond.StopSeq.SequenceEqual(drlf) && buffer[0] == dtx)
                        {
                            checkWhile = true;
                        }
                    }
                }
                while (checkWhile);
    
                // считывание последнего байта после ETX
                if (stopReceived && readCnt < MaxRxDLen && StopCond.StopSeq.SequenceEqual(etx))
                {
                    string logText2;
                    int readCnt2 = Connection.Read(buffer, readCnt, 1, PollingOptions.Timeout,
                        ProtocolFormat.String, out logText2);
                    if (readCnt2 > 0)
                    {
                        readCnt += readCnt2;
                    }
                }
    
                // При программной эмуляции 7-E-1 сбрасывать старший бит
                if (prog7e1)
                {
                    for (int i = 0; i < readCnt; i++)
                    {
                        buffer[i] = Convert.ToByte(buffer[i] & 0x7F);
                    }
                }
                // -----------------------------
                logText = BuildReadLogText(buffer, 0, readCnt, ProtocolFormat.String);
            }
    

    BuildReadLogText — а это надо повторить, так как прямого доступа как в 5-й нет

            /// <summary>
            /// Builds a log text about reading data.
            /// </summary>
            protected static string BuildReadLogText(byte[] buffer, int offset, int readCnt, ProtocolFormat format)
            {
                return $"{CommPhrases.ReceiveNotation} ({readCnt}): " +
                    ScadaUtils.BytesToString(buffer, offset, readCnt, format == ProtocolFormat.Hex);
            }
    

    Вроде ничего не забыл, но если будет на что ругаться, пишите, найду в коде. Ну и из-за того, что по нескольким разным массивам идет остановка у меня там цикл проверок… Если всегда одинаковое, то можно упростить

    #27131
    manjey73
    Участник

    Блин, вам всего этого не надо…. у вас есть

    ADR КФ N Байт 1 Байт 2 … … Байт N CRCМЛ CRCСТ

    Размер блока передаваемых данных. Суть та же, что и в Modbus, считали первые три байта, узнали размер блока + CRC и дочитали остальное…

    #27132
    manjey73
    Участник
    // Прием заголовка
                            buf_in = new byte[4];
                            Connection.Read(buf_in, 0, buf_in.Length, PollingOptions.Timeout, ProtocolFormat.Hex, out logText); //считать значение из порта
                            Log.WriteLine(logText);
    
                            // TEST TEST TEST костыль - повтор кода при приеме
                            // Прием тела ответа с  CRC и завершающим символом
                            buf_in_res = new byte[buf_in[1] + 2]; // Буфер тела ответа TEST TEST
                            readcnt = Connection.Read(buf_in_res, 0, buf_in_res.Length, PollingOptions.Timeout, ProtocolFormat.Hex, out logText); //считать значение из порта
                            Log.WriteLine(logText);

    В нужном байте у вас размер, добавляете +2 байта на контрольную сумму. Ну и входной буфер у вас должен быть по размеру, который вам надо прочесть и определить размер

    #27133
    JurasskPark
    Участник

    Размер блока передаваемых данных. Суть та же, что и в Modbus, считали первые три байта, узнали размер блока + CRC и дочитали остальное…

    Нет там такого. 🙂

    #27134
    manjey73
    Участник

    Где нет? в Modbus или у вас в протоколе? вроде и там и там есть, я же показал N это и есть байт размера блока данных

    N – размер блока передаваемых данных (от 1 до 255);

    Из pdf по вашему вычислителю, страница 6, Общий вид ответа

    • Этот ответ был изменен 1 неделя, 5 дней назад от manjey73.
    • Этот ответ был изменен 1 неделя, 5 дней назад от manjey73.
    #27137
    manjey73
    Участник

    При чем вам надо принимать 6 байт, проверять ответил ли прибор ошибкой на запрос, если не ошибкой, то смотреть 3-й байт ответа (2-й массива), рассчитывать длину и делать тут же запрос на оставшуюся часть ответа, выполняя остановку. Тогда таймаут мешать вам не будет.

    #27138
    manjey73
    Участник

    Для других ответов N у вас X4 то есть вам надо в зависимости от запросов понимать что из себя представляет N, просто количество или количество параметров х 4 байта.

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