48 попугаев при опросе

  • В этой теме 27 ответов, 3 участника, последнее обновление 2 года назад сделано Mikhail.
Просмотр 15 сообщений - с 1 по 15 (из 28 всего)
  • Автор
    Сообщения
  • #22296
    manjey73
    Участник

    Ситуация такая, опрашиваю устройство, у которого длина ответа вариативная (вечно мне такие попадаются)…

    Так вот, ответы в общем короткие и сделал опрос по одному байту после заголовка с проверкой на маркер в виде байта 0xC0
    Количество маркеров зависит от наличия определенных байт в блоке данных.

    Вот код

    private void ReadAfterHeader(int needCnt, out int Cnt, out string log) 
            {
                int startRead = 5;
                Cnt = 0;
                int cnt = 0;
                int cnt1 = 0;
    
                for (int i = 0; i < needCnt; i++)
                {
                    cnt1 = Connection.Read(inBuf, startRead, 1, ReqParams.Timeout, CommUtils.ProtocolLogFormats.Hex, out logText);
                    if (inBuf[startRead] == 0xC0)
                    {
                        i--;
                    }
                    cnt += cnt1;
                    startRead++;
                }
                Cnt = cnt;
                log = Connection.BuildReadLogText(inBuf, 5, Cnt, CommUtils.ProtocolLogFormats.Hex);
            }

    Есть возможность целенаправленно задать эти определенные байты в ответе (это счетчик, начальное значение которого можно задать)
    Так вот через 48-мь сессий опроса прибора происходит ошибка чтения, независимо сколько запросов я делаю, 5-ть или 3-ри…

    В чем может быть проблема? Если что могу дать драйвер и доступ к прибору…

    Ошибка

    Отправка (9): C1 06 01 00 02 8A 03 60 48
    Приём (5/5): C2 06 01 00 05
    2022-03-11 12:40:01 Ошибка при выполнении сеанса опроса КП 153 "RIELTA": Ошибка при считывании данных: Заданный аргумент находится вне диапазона допустимых значений.
    Имя параметра: size
    #22299
    manjey73
    Участник

    Нашел причину, но не понимаю, как это работает. Количество Сессий зависит от размера буфера.

    Были объявлены переменные

            private const int InBufLen = 20;    // Длина буфера принимаемых данных
            private byte[] inBuf;               // буфер входных данных
    

    В разделе OnAddedToCommLine() было объявление
    inBuf = new byte[InBufLen];

    Connection.Read вроде как бы намекает, что чтение происходит в определенный offset но где-то происходит переполнение буфера…

    Перенес объявление буфера непосредственно в Session и ошибка ушла…
    Что самое интересное, ловил маркер циклами while и for чтением по одному байту, переделал на вариант от : Connection.BinStopCondition, ошибка все равно происходила. Количество сессий (попугаев), после которых происходила ошибка зависит от размера буфера InBufLen первоначально был 60 байт, отсюда и 48 попугаев 🙂

    Но вот с чем связана такая ошибка непонятно????

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

    Connection.Read вроде как бы намекает, что чтение происходит в определенный offset

    Верно. Новые данные записываются в указанные ячейки буфера.

    Перенес объявление буфера непосредственно в Session и ошибка ушла

    Так будет постоянно выделяться новая память, что нежелательно.

    Думаю, что ошибку нужно отловить и вывести в журнал дополнительную информацию, которая поможет найти причину.

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

    Переменная i цикла for не должна меняться в теле цикла. Сделайте хотя бы цикл while вместо for.

    #22304
    manjey73
    Участник

    Михаил, я думаю ошибка в ядре Коммуникатора при задании буфера в секции OnAddedToCommLine()

    цикл for это второй вариант при поиске проблемы, сейчас работает по схеме остановки массива байт в созданном классе от Connection.BinStopCondition

    То есть ошибка проявлялась при любых из трех вариантов и определенном ответе.

    з.ы. сейчас отключу запрос для данного ответа и верну буфер где был и проверю.

    Если что могу дать и код драйвера и доступ к железке для поиска…

    Почему это i нельзя менять в for? кто это запретил ? 🙂

    • Этот ответ был изменен 2 года назад от manjey73.
    #22306
    manjey73
    Участник

    Сейчас код такой.

            private readonly static MyStopCondition StopCond;
            private static List<byte[]> stopList = new List<byte[]>();
            private static byte[] cx0 = new byte[] { 0xC0 }; // 0xC0, 0x00
    
            public class MyStopCondition : Connection.BinStopCondition // TEST логики остановки по двум или более массивам
            {
                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;
                }
            }
            private void ReadAfterHeader(int needCnt, byte[] buffer, byte lastByte, out int readCnt, out string logText)
            {
                bool stopReceived = false;
                bool checkWhile;
                readCnt = 0;
                int offset = 5;
    
                do
                {
                    checkWhile = true;
                    int readCnt1 = Connection.Read(buffer, offset, needCnt, ReqParams.Timeout,
                            StopCond, out stopReceived, CommUtils.ProtocolLogFormats.Hex, out logText);
    
                    if (stopReceived)
                    {
                        offset = offset + readCnt1;
                        needCnt = offset - 1;
                    }
                    else checkWhile = false;
    
                    readCnt += readCnt1;
                }
                while (checkWhile);
    
                logText = Connection.BuildReadLogText(buffer, 5, readCnt, CommUtils.ProtocolLogFormats.Hex);
            }
    
    

    Далее в разделе задан список

            static KpRieltaLogic()
            {
                stopList.AddRange(new[] { cx0 }); // , cx1, cx2
                StopCond = new MyStopCondition(stopList);
            }

    При включении запроса, в ответе которого будет маркер 0xC0 при размере буфера 20 байт, заданным в OnAddedToCommLine() через 8 сессий получаем ошибку

    Отправка (9): C1 06 01 00 02 8A 03 60 48
    Приём (5/5): C2 06 01 00 05
    2022-03-12 11:19:00 Ошибка при выполнении сеанса опроса КП 153 "RIELTA": Ошибка при считывании данных с условием остановки: Заданный аргумент находится вне диапазона допустимых значений.
    Имя параметра: size
    

    При этом MyStopCondition можно убрать и сделать либо простым циклом, либо циклом while, меняя там количество байт для Connection.Read приводят все равно к ошибке…
    Если буфер задан в Session то все работает (всю ночь на остановке по массиву байт отработало без нареканий.)

    Каким образом нарушается буфер, при включении его в OnAddedToCommLine() при том, что в Connection.Read явно указывается с какого байта заполнять буфер ????

    #22311
    manjey73
    Участник

    Включение буфера в OnCommLineStart() приводит к тому же результату с ошибкой.

    Такая вот картина…

    Коммуникатор
    Версия : 5.2.1.2

    #22312
    Romiros
    Участник

    Наверное тут лучше запустить debugger и не гадать. Всё пошагово будет видно.

    #22313
    Romiros
    Участник

    И можно ещё проверить, если очищать буфер перед опросом, ошибка будет повторяться?

    #22315
    manjey73
    Участник

    А как очищать? Циклом нули писать?
    Фокус в том, что ответ без маркера 0xC0 читается через тот же код, будь это цикл или по остановке через массив байт, не приводит к ошибке.
    Попробую через дебаггер подключить и понять где остановится, но честно не знаю куда остановку ставить, так как проблема не в моём коде точно.

    #22316
    Romiros
    Участник

    Очистить как-то так
    Array.Clear(inBuf,0,inBuf.Length)

    Ошибка у Вас в коде. Дебагер поможет. Сам через это проходил. У меня проблема была конечно в другом, то что в неуправляемом коде размер типов в байтах другой, чем в управляемом. И у меня так же индекс выходил за диапазон. Я просто не знал этого ньюанса и по логике кода все должно было работать. Потом подключил дебагер и просто офигел, насколько отличается размер.

    #22322
    manjey73
    Участник

    Ошибка буфера ситуацию не изменила, осталось все по прежнему.

    К сожалению, у меня нет под рукой Allen Bradley чтобы проверить, там был похожий механизм, но маркер в коде был 0x10, не помню на какой версии, работало сутки на пролет без проблем.

    • Этот ответ был изменен 2 года назад от manjey73.
    #22324
    manjey73
    Участник

    Вопрос, а к какому процессу надо подключиться и как? ScadaComm запущен же как сервис и я не вижу его…

    #22325
    manjey73
    Участник
    System.InvalidOperationException: "Ошибка при считывании данных с условием остановки: Заданный аргумент находится вне диапазона допустимых значений.
    Имя параметра: size"
    
    ArgumentOutOfRangeException: Заданный аргумент находится вне диапазона допустимых значений.
    Имя параметра: size

    Исключение в Connection.Read
    Почему-то буфер стал всего 12 byte[12]

    #22326
    manjey73
    Участник

    У меня простой вопрос, почему буфер, объявленный в OnAddedToCommLine() при передаче в Connection.Read в режиме с остановкой начинает уменьшаться на один байт каждую сессию ?

    Это мое предположение, я то его никак не уменьшаю в коде…

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