Добрый день.
Можно, но только по протоколу ОВЕН (по Modbus эти параметры недоступны).
Вид для печати
Добрый день.
Есть ли возможность получить доступ к содержимому логов библиотеки CmpLog для отображения их на визуализации ПЛК? Наподобие того, как это сделано в CoDeSys (Device -> Log).
Добрый день.
Логи лежат в папке tmp (файлы PlcLog_x.csv).
В визуализации можно отображать их с помощью элемента Текстовый редактор - но выглядеть, скорее всего, будет не очень здорово.
В баг-трекере CODESYS есть запрос на создание отдельного элемента для отображения логов в визуализации - но в работу его пока не взяли.
Спасибо, поищу тогда.
> но в работу его пока не взяли
Жаль, очень полезная штука будет.
Добрый день!
Посоветуйте, пожалуйста, защиту от бесконечного цикла и последующей перезагрузки контроллера. Безусловно, лучшая защита - это правильный алгоритм. Но сразу все предусмотреть не получается, особенно, когда данные приходят по сети. Есть понимание, что сейчас, в случае искажения данных выход из While может и не произойти, парсер у меня пока написан наживую. Можно ведь, вероятно, если здесь перехват ошибок невозможен, использовать таймер с Exit? Или есть еще методы?
Согласен, но как тогда обработать данные, полученные по ТСP, только в главном цикле - пока не понимаю. Ведь этот цикл может выполнятся за разное время, а TCP блок, вероятно, работает асинхронно. Использовать глобальный указатель на уже обработанный байт? И в следующем цикле обрабатывать следующий... но тут мы ограничены временем выполнения цикла, которое может и вырасти. Кроме того, мне кажется, при таком подходе могут стать заметны "визуальные эффекты" при выдаче строк в визуализацию. В While они собираются практически мгновенно, я думаю.
Опишите подробно, что вы делаете и что именно вызывает у вас затруднения.
Простейщая программа - TCP клиент (прям из хелпа CODESYS), от внешней железки приходят данные. Есть глобальный флаг, что пришли данные. По этому флагу в главном цикле, начинается побайтовый разбор пришедших данных в массиве RX, массив принадлежит клиенту. Выходящяя строка (точнее строки) собирается через индексы, посимвольно, в цикле While, цикл является частью парсера. Протокол довольно сложный. Вот кстати еще подумал, хотя на глаз это и не заметно. При каждом изменении строки (посимвольно) в WEB-визуализации также происходят изменения надо думать! Стоит сделать промежуточну переменную, и потом однократное присваивание? Но главное, это все устойчиво работает (сутками) по LAN. Парсер так сразу и не соображу как оснастить всеми проверками, сейчас если, например, выпадет байт окончания подсообщения (протокол многословный, упакованный) или что-то еще - зацикливание обеспечено.
Задача прояснилась, но я все равно пока не понимаю, зачем вам там цикл WHILE.
Выложите пример кода, чтобы стало яснее, для чего вы его используете.
В приемном буфере последовательность байт. Данные могут быть трех типов - включено/выключено, число, закодированное как два байта, или символьные строки переменной длины. В совокупности, это, так сказать телеграмма. Порядок этих трех типов данных в общем случае может быть разным в телеграмме, какой-то тип может и осутсвовать, что-то повторяется как тип (но у каждого типа сигнала есть индивидуальный индекс, ). Т.е. длина всей телеграммы очень вариабельна, как и число и тип данных внутри. Стараюсь ее побыстрее распарсить, пока не пришла следующая телеграмма. Как-то так.
В общем, пожалуй, да. Длина сообщения конечно известна. Правда, двигаться внутри приходится, то по по два байта, то по четыре, то вообще на заранее неизвестное число байт, это если в телеграмме символьная строка или несколько строк. Эти шаги выясняются при разборе. Контрольной суммы как ни странно, железка не дает. Т.е. я сразу не могу отбросить всю телеграмму. Окончание строки может быть как "FB" так и отсутсвовать, если данные пришли сами, без запроса. В этом случае будет просто четное число бвйт, но это чисто так, примечание.
Условие выхода из цикла в общем понятны, и их можно задать. Но если данные будут искажены, то выход может и не состоятся. Это в реальных условиях. А просто обрабатывать в главном цикле побайтно мне кажется рискованно. У меня время цикла среднее менее 200 мкс. Т.е. как я понимаю, он выполняется примерно 5000 раз в секунду, грубо. В нем обрабатывать конечно можно было бы, но ведь потом программа может усложнится и цикл увеличится. Возвращаясь к циклу, условия выхода там в общем то заданы... но если в данных будет ошибка, то парсер собьется и последствия - зацикливание. Вот пока думаю.
Мне эта фраза непонятна - если данные искажены, то парсер (основанный на заранее известных правилах) должен определить пакет как невалидный и на этом прекратить работу.Цитата:
Но если данные будут искажены, то выход может и не состоятся.
P.S. - если для вас критично быстродействие и с учетом того, что у вас Raspberry Pi - вы можете парсер (или вообще всю эту часть, включая обмен) переписать на С и передавать данные в CODESYS через разделяемую память.
Системное время в веб-конфигураторе и время в таргет-переменной st.Rtc.dtDateAndTime это разное время? Почему при ручной синхронизации времени dtDateAndTime равна времени Ntp сервера, а системное время в конфигураторе дополнительно смещено по utc?
Вложение 56120
Вложение 56121
Причем если предположить, что это разные переменные, и веб-конфигураторе выставить время GMT 0, с применением настройки, после синхронизации опять произойдет смещение согласно siSetUtcOffset
Вложение 56122
Ntp сервером выступает мой ПК с utc +3
Сброс проекта к заводским, загрузка проекта и подключение к плк не отключаясь от логина, заходим в веб-конфигуратор ПЛК выставляем часовой пояс, синхронизируем время с браузером сохраняем и применяем настройки, получаем:
Вложение 56123
(все синхронизации выключены) уже отличается
Включаем блок ручной синхронизации utc+3 получаем после синхронизации
Вложение 56124
Добрый день. Подскажите пожалуйста документацию по работе с SQLite в CoDeSys 3. Интересует, пожалуй, всё -- от создания экземпляра БД, задания структуры таблиц до записи/чтения данных по запросам из созданной БД. Вроде бы библитотеки CAA Storage и CAA Storage Imp должны быть при деле, но пока не соображу, как к ним подступиться.
> Такой документации нет - как, собственно, и явного доступа к SQLite.
Весело. Но CAA Storage-же используется как-то? Там всякие интерфейсы объявлены, SQLSTATEMENT, опять же. На который нигде ссылок нет, правда.
Не оставляют меня мечты сделать свой логгер с WSTRING и фильтрацией.
> Это можно и без SQLite сделать - достаточно CAA File
Да можно, конечно, но фильтрация вывода... Свои фильтры городить же придётся. Я надеялся, что какой-никакой доступ к SQL-хранилищу есть, а они...
Вложение 56137 Здравствуйте, подскажите пожалуйста, где найти библиотеку visutrendstorageacess 3.5.16.20 ?
Здравствуйте.
Эта библиотека входит в дистрибутив CODESYS.
У вас проблема не в ней, а в том, что в эмуляции тренды не работают.
Используйте виртуальный контроллер:
http://www.owen.ru/forum/showthread....l=1#post296706
Здравствуйте, подскажите как быть. Делал проект года 4 назад на спк 105. После этого винда менялась раз 5. Проект сохранил к сожалению не как архив(((. Теперь после установки Codesys с библиотеками при компиляции пишет ОООчень много ошибок. В том числе я так понимаю и на библиотеки. Где теперь их искать? Или лучше вообще заново писать? Почему при создании абсолютно нового проекта для СПК105, он пишет опять таки много ошибок при компиляции?Вложение 56180 Спасибо.
Добрый день!
Подскажите, пожалуйста. Есть главный цикл, внутри главного цикла другой цикл, где побайтно собирается строка, привязанная к элементу "Текстовое поле" в визуализации (строго говоря, там массив строк, элементов текстовое поле 16 штук). Должна ли быть меньше нагрузка на подсистему КДС, связывающую программу с визуализацией, если сначала собирать строку в независимую промежуточную переменную, а потом, после выхода из внутреннего цикла, присвоить текстовому полю уже собранную строку. У меня поступает в парсер пачкой 16 строк по ~ 8-10 символов. Пробовал и так, и так - честно говоря, особой разницы во времени цикла (среднем, после сброса) не заметил. Как есть примерно 150 микросекунд, так и есть.
Петр Петрович Я могу ответить невпопад, так как прочитал "строка" и про это и хотел сказать.
а) Конечно, сначала лучше собирать всё во временную переменную, а потом один раз её визуализации присваивать. Иначе же визуализация каждый раз будет пытаться обновляться. Скорости это может и не добавить, но так правильнее.
б) Работа со строками чем сделана? Штатные функции тормозят, и всем советуют переходить на работу со строками по указателям (библиотека StringUtils - НЕ OwenStringUtils, а просто). У меня при переходе со штатных CONCAT на StringUtils загрузка процессора в одном из проектов упала с 97% до 70%. Сразу прям.
Спасибо за ответы! Да, там внутри парсера цикл FOR. Насчет временной переменной понял. Тоже думал, что пока подсистема визуализации протолкнет туда каждый символ... эти переключения на другую задачу для каждого символа стабильности не добавят. А работа со строками там как таковая отсутствует - проверяется заголовок в массиве принятых по TCP байт, далее результирующая строка собирается посимвольно, через индексы (в цикле FOR, т.к. заранее известна только максимально возможная длина сообщения, выход из цикла по стоповому байту и EXIT) и пищется признак конца строки.
Вот например:
\xE0\x00\x3A\x58\xD0\x01\x75\x44\xD0\x02\x75\x44\x C0\x03\x00\x3A\xC0\x04\x00\x44\xC0\x05\x00\x11\xF0 \x06\x7F\x4E\xF0\x07\x7F\x4E\xF0\x08\x7F\x58\xF0\x 09\x7F\x67\xC0\x0A\x00\x11\xC0\x0B\x00\x2E\xC0\x0C \x00\x4C\xF0\x0D\x7F\x52\xF0\x0E\x7F\x5D\xC0\x0F\x 00\x11\xF0\x10\x7F\x4E\xF0\x11\x7F\x4E\xF0\x12\x7F \x58\xF0\x13\x7F\x67\xC0\x14\x00\x11\xC0\x15\x00\x 2E\xC0\x16\x00\x4C\xC8\x17\x20\x31\x50\x4F\x2E\x33 \x46\x4D\xFF\xC8\x18\x31\x30\x32\x2C\x33\x30\xFF\x C8\x19\x20\x31\x50\x4F\x2E\x33\x46\x4D\xFF\xC8\x1A \x20\x31\x50\x4F\x2E\x33\x46\x4D\xFF\xC8\x1B\x20\x 31\x50\x4F\x2E\x33\x46\x4D\xFF\xC8\x1C\x20\x31\x50 \x4F\x2E\x33\x46\x4D\xFF\xC8\x1D\x20\x31\x50\x4F\x 2E\x33\x46\x4D\xFF\xC8\x1E\x20\x31\x50\x4F\x2E\x33 \x46\x4D\xFF\xC8\x1F\x20\x31\x50\x4F\x2E\x33\x46\x 4D\xFF\xC8\x20\x20\x31\x50\x4F\x2E\x33\x46\x4D\xFF \xC8\x21\x20\x31\x50\x4F\x2E\x33\x46\x4D\xFF\xC8\x 22\x20\x31\x50\x4F\x2E\x33\x46\x4D\xFF\xC8\x23\x20 \x31\x50\x4F\x2E\x33\x46\x4D\xFF\xC8\x24\x20\x31\x 50\x4F\x2E\x33\x46\x4D\xFF\x80\x28\x80\x2B
Кусок, начинающийся с C8h и заканчивающийся FFh - это строка символов, данные + индекс сигнала. А \x80\x2B (их хорошо в конце видно) это логическая единица, второй байт индекс сигнала. Вот я и прохожу последовательно весь массив входных данных, разбираю что к чему. В общем, алгоритм простейший линейный, нашли сигнатуру типа сигнала, определили индекс в какой элемент визуализации выдавать, определили конец строки в процессе прохода, если сигнал - строка символов. А как еще?