воскресенье, 18 февраля 2018 г.

История с крышечками

Нельзя просто так взять, и бросить контакты шины неприкрытыми. Для этого существует Bus end cap или Bus end cover — защитная крышка. По сути, это просто кусок промышленной пластмассы, защищающий контакты шины последнего модуля, но есть нюансы.

Во времена перехода от шины K-bus к шине EtherCAT (E-bus), выпускался широкий 12 миллиметровый модуль (Bus End Terminal), похожий на обычный модуль, только без электроники на борту. Заодно обратите внимание на слово Terminal:


Был он толстый и занимал дополнительную позицию на дин-рейке. Это всем мешало, и тогда было принято решение перейти на оптимальные по ширине крышки:


Соответственно, слева-направо: EL9011, ELM9012 и ELX9012, а в конце пунктирный образец для выпиливания лобзиком и, по совместительству, схема электрическая принципиальная. Несмотря на отсутствие электроники на борту, System Manager как-то эти модули обнаруживает и добавляет в конфигурацию. Черная крышка для измерительных модулей ELM, синяя — для электропожаровзрывобезопасных модулей ELX, серая — для обычных модулей EtherCAT. Желтая крышечка TwinSAFE пока что не существует или еще не прошла сертификацию.

Внезапно, в списке продукции всплывает EL9012, которая выглядит точь-в-точь как EL9011, но если первая называется английским словом cover (укрытие), то вторая всего-лишь cap (крышечка). Какую ставить, и есть ли разница? Давайте сравним...

12-я толще: 8 мм против 5 мм одиннадцатой. Зато 11-я лучше сертифицирована: три сертификата CE, UL, Ex, а у 12-й только один CE. Так как 12-я в три раза дороже 11-й, делаем вывод, что разница в стоимости зависит только от количества пластика. Ну и последнее, 12-я закрывает весь бок терминала целиком и прячет под защиту и шину, и контакты подпитки модулей (cover for power and E-bus contacts), а EL9011 закрывает только контакты шины (cover for the E-bus contacts). Вот и вся разница. Достаточно разместить фото крышек сбоку и разница была бы понятна сразу.

По остальным защитным, разделительным и прочим крышкам можно прочитать в EL9xxx.

четверг, 15 февраля 2018 г.

Категории библиотек TwinCAT 3

Предположим, вы разработали библиотеку или портировали чужую, типа библиотеки OSCAT под TwinCAT 3. Наступает ответственный момент оформления библиотеки, вы заполняете графы описания и решаете выбрать категорию библиотеки (Library Categories), чтобы в дальнейшем быстро находить библиотеку в локальном репозитории,

А списка категорий нет.

Можно экстрагировать категории из других библиотек: они лежат в x:\TwinCAT\3.1\Components\Plc\Managed Libraries, а можно загрузить из некоего файла (From Description File...) с расширением *.libcat.xml, но файла также нет. По крайней мере, для оборудования и библиотек Бекхофф, я их так и не нашел.

Поэтому выдавил из библиотек свой собственный и неофициальный список.



Список можно найти на гитхабе, он лежит в открытом виде и готов к использованию — Tc_LibcatXml. По возможности я буду поддерживать его в актуальном состоянии, либо должен найтись способ получать эти категории из официального источника. Сейчас же доступны три не официальные версии — какое-то наследие TwinCAT 2, затем устаревший TwinCAT 3 и актуальная на данный момент версия beckhoff-tc31.libcat.xml.

вторник, 13 февраля 2018 г.

ExST: расширенный ST

Язык ST (Structured Text) получил много полезных расширений, что в последствии назвали Extended ST. И это не только модное ООП. Я свалил все в кучу: и расширения, и просто малоизвестные вещи, к тому же, всё это подходит не только для TwinCAT, но и для CoDeSys-мира вообще. Начнем с мальчика для битья — оператора GOTO...

Язык ST все еще поддерживает оператор GOTO. Не прямо так гоу-ту, а как в ассемблере — JMP куда-то там на метку в коде. Выглядит это так:

label_infinitum:
(* полезный код *)
JMP myLabel_4321;

(* бесполезный кот *)

myLabel_4321:    // это метка для перехода
(* еще полезный код *)
JMP label_infinitum;

Избегайте бесконечно-вечных циклов.


CONTINUE


CONTINUE относится к расширению языка, а EXIT нет. Если вы не знали, то EXIT немедленно прекращает выполнение текущего цикла и выходит из него (текущая итерации FOR, WHILE или REPEAT не будет выполнена до конца). CONTINUE же прекращает текущую итерацию и немедленно переходит к началу цикла, выполнять следующую итерацию:

FOR i := 0 TO 100 BY 2 DO
    IF i MOD 3 = 0 THEN
        CONTINUE; // пропускаем инкремент переменной a и переходим к следующей итерации
    END_IF
    a := a + 1;
END_FOR

Осторожнее с вложенными циклами: EXIT выходит только из одного вложения. Для выхода из нескольких вложенных циклов, помогает команда JMP.

FOR j := 0 TO 100 DO
    FOR i := 0 TO 100 DO
        IF ??? THEN
            EXIT; // завершит цикл FOR i ...
        ELSE
            JMP finita_incantata;
        END_IF
    END_FOR
    // EXIT приведет сюда
END_FOR

finita_incantata:

Оператор MOD находит остаток от деления, как оператор % в C++.


Оператор установки S=


Запись A S= X; аналогична:

IF X THEN
    A := TRUE;
END_IF

Как только A станет равным TRUE, то никакое значение X уже не изменит A. Оператор S= никогда не сможет сбросить A в FALSE.

A        X       A
FALSE S= FALSE → FALSE
FALSE S= TRUE  → TRUE
TRUE  S= FALSE → TRUE
TRUE  S= TRUE  → TRUE


Оператор сброса R=


Запись F R= X; аналогична:

IF X THEN
    F := FALSE;
END_IF

Как только F станет равным FALSE, то никакое значение X уже не изменит F. Оператор R= никогда не сможет установить F в TRUE.

F        X       F
FALSE R= FALSE → FALSE
FALSE R= TRUE  → FALSE
TRUE  R= FALSE → TRUE
TRUE  R= TRUE  → FALSE


Присваивание


Присваивание как выражение (assignment as expression) можно делать так:

IF bVar := (i = 2) THEN
    i := i + 1;
END_IF

bVar — булева переменная, получает значение от выражения (i = 2), то есть будет равна TRUE когда (i = 2). Затем bVar оценивается в IF. Лучше не мудрить и не пихать в одну строку несколько команд сразу. Пишите так, чтобы было проще читать впоследствии. Компилятору все-равно как  вы написали, работать это будет одинаково, а вероятность ошибиться намного выше в сложносочиненной записи:

bVar := (i = 2);

IF bVar THEN
    i := i + 1;
END_IF


Можно присваивать нескольких переменных одновременно:

a:= b:= c:= k + 12;

Но не дайте обмануть себя видом и формой записи — здесь нет присваивания, передающегося справа-налево по цепочке! Аналогичная, но более длинная запись, выглядит так:

a := k + 12;
b := k + 12;
c := k + 12;

Выражение (k + 12) будет вычисляться три раза, поэтому выгоднее записать:

c := k + 12;
a:= b:= c;

Теперь вспомним операторы установки/сброса. Как будет работать следующая строка? Ответ в конце поста.

A S= F R= X;


Типизированные литералы


Звучит жутко умно, но это всего-лишь способ задать точный тип числа.

A := 123; — не говорит нам какого типа число 123 (литерал). Это точно не BOOL и скорее всего не REAL / LREAL (нет десятичной запятой). Возможны SINT, USINT, BYTE, INT, UINT, WORD, DINT, UDINT, DWORD. Так кто же из них?

Обычно тип литерала будет зависеть от типа переменной A. Поэтому можно просто уточнить запись литерала: A := 123.0; и тогда мы получим REAL. Но что если хочется BYTE, а переменная типа UINT?

Для этого тип можно обозначить точно: A := BYTE#127;

Такую запись можно использовать везде, где допустимо использование констант. Если TwinCAT обнаружит потенциальную потерю данных, то выдаст сообщение об ошибке или просто предупреждение, если всё не так страшно.


CASE ... ELSE


Если конкретный шаг CASE для какого-то значения переменной не существует, то CASE игнорируется целиком, за исключением если... Блок ELSE в CASE позволяет задать действие по умолчанию, если номер шага в CASE не задан:

CASE state OF
0:
    DoSomething();
100:
    DoSomething2();
...
2000:
    DoSomethingAgainNAgain();
ELSE
    DontKnowWhatHappenedLastTime();
END_CASE

Если вы знакомы с C++, то это аналогично: switch case ... default.


OR_ELSE


Работает аналогично OR, но если левая часть OR_ELSE уже равна TRUE, то правая часть не проверяется и не выполняется:

VAR
    a, z, b : BOOL;
    i : INT;
END_VAR

z := a OR_ELSE (b := (i = 2));

Если А равно TRUE, то правая часть OR_ELSE не будет выполняться и B никогда не сможет стать TRUE. Можно оптимизировать производительность, исключив лишний вызов функций. И теперь мы знаем, что для "обычного" OR, независимо от значения операндов, вызываются и проверяются обе части: и левая, и правая.


AND_ELSE


Как AND, но правая часть AND_ELSE обрабатывается только при условии, что левая часть  равна TRUE. Например, это удобно для проверок указателей:

IF (ptr <> 0 AND_THEN ptr ^= 99) THEN ...

Когда указатель не равен нулю и_тогда выполнить сравнение адреса указателя. Это позволяет избежать проблем с нулевым указателем. В обычном AND всегда обрабатываются обе части независимо от их значения.


Ответ


A S= F R= X;

// работает как

A S= X;
F R= X;

суббота, 10 февраля 2018 г.

SLC USB 3.0 флешки

Бекхофф переходит на очень надежные SLC USB-флешки для переноса и хранения полезных данных. На чем были построены предыдущие не известно, но вариантов немного: или MLC — как в SSD, или TLC — как в бытовых флешках. По аналогии с 200x рублевыми купюрами, новые флешки выглядят так:

Изображение: Beckhoff Automation

Еще раз — SLC (single-level cells) в теории надежнее, чем MLC и TLC. Там что-то порядка 100 000 перезаписей, против 3 000 и 1 000, соответственно. А еще SLC быстрее всех.

Флешки будут с интерфейсом USB 3.0 и объемом 4, 8, 16, 32 Гб и полной совместимостью с USB 2.0 и USB 1.1. Для желающих, есть разновидность с предустановленными спасительными BST (Beckhoff Service Tool): такие же объемы, но интерфейсы только USB 3 и 2. USB 1.1 для BST не поддерживается.

А раньше были такие:

Изображение: Beckhoff Automation

Или даже такие, возможно, раздаточно-презентационные:


среда, 7 февраля 2018 г.

Деление на ноль

Давно ли вы делили на ноль?



Случайные ошибки


PROGRAM MAIN
VAR
    a, b, c : INT;
END_VAR

a := 12 / 0;

Такую случайную ошибку среда разработки отловит еще на этапе компиляции:



... но стоит только подставить переменную, как деление на ноль произойдет во время работы. И...

PROGRAM MAIN
VAR
    a, b, c : INT;
END_VAR

a := 12 / b; // <<<< !!!!

...TwinCAT переходит с состояние "стоп" (Stop), выбрасывая в консоль сообщение об ошибке:
Error 01.02.2018 15:02:24 456 ms | 'Port_851' (851): Exception (Exception Code: 0xc0000094, Integer divide by zero) in PLC Application Untitled1 Instance, Task PlcTask (EBP: 0xa9b5eeb8, EIP: 0xa7927056, ESP: 0xa9b5ee90)

Что произойдет если у вас несколько задач (тасков)? Остановится ли только "эта" задача или все сразу? Как поведет себя система в многоядерной архитектуре? И что с изолированными (isolated) выделенными ядрами?


Изолируем и форкаем


Добавляю и запускаю вторую, параллельную задачу. И сразу же роняю первую, установив переменную b := 0. Первая задача падает в точку останова, но вторая задача продолжает работать — счетчик тикает:



Пробую восстановить задачу после падения, устранив ошибку: значение переменной b := 1, затем пытаюсь продолжить выполнение первой задачи. Не получается. Пробую подтвердить на экране ПЛК сообщение об ошибке деления на ноль (кнопка ОК). TwinCAT целиком переключается в режим конфигурирования (синий значок), но теперь уже с остановкой всех задач: и ошибочных, и корректных. При этом:
  • Reset Cold — не помогает.
  • Rest Origin — помогает, так как он начисто сносит весь рантайм задачи (это заметно по предложению пересоздать порт при последующем запуске). Затем можно перезапустить задачу заново, но непонятно, что в это время творится с другими задачами.

При всех этих телодвижениях среда разработки VS 2015 ведет себя очень нестабильно, а может быть это контроллер ведет себя некорректно. Не уверен — кто из них. Возможно оба. В надежде повысить стабильность, я выделил одно из ядер ПЛК целиком под TwinCAT: 100% производительности в печенку процессора. Ничего не меняется. Пытаюсь перезапустить ошибочную задачу, но TwinCAT переходит в режим конфигурации, с полной остановкой всех ядер и задач. Версия TwinCAT контроллера: 3.1.4020.32.

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


Отлаживаем


Для отладки и только отладки (почему, я расскажу позже) TwinCAT предлагает нам стандартное средство из проверочных функциональных блоков — Object POUs for implicit checks. Теперь их можно создавать тыкая мышкой в: POUs → Add → POU for implicit checks... → +Division Checks. После этого в ПЛК-проект добавятся несколько автоматически сгенерированных функций. Необходимо перекомпилировать проект и перезагрузить его в контроллер целиком (download). Загрузка проекта на лету (online change) с сохранением данных (значений переменных) на этот раз недоступна, так как в проекте появились новые программные объекты (POUs).

Я экспериментирую с делением целого типа, вот пример такой функции:

// Implicitly generated code : DO NOT EDIT
FUNCTION CheckDivDInt : DINT
VAR_INPUT
    divisor:DINT;
END_VAR

// Implicitly generated code : Only an Implementation suggestion
{noflow}
IF divisor = 0 THEN
    CheckDivDInt:=1;
ELSE
    CheckDivDInt:=divisor;
END_IF;
{flow}

Несмотря на предостережение: "НЕ РЕДАКТИРОВАТЬ", — редактировать можно и нужно. Например, добавить сообщение об ошибке в лог и вытащить номер текущего шага из других программных объектов.

Интересно, что эта функция будет вызываться для каждой операции деления! Значением входного параметра divisor будет значение делителя/знаменателя из операции деления, а результат функции (возвращаемое значение) будет подставляться вместо делителя в операции деления. Попробуйте в теле функции заменить CheckDivDInt:=divisor; на CheckDivDInt:=2; и все ваши операции деления, независимо от значения делителя, превратятся в банальным делитель на двойку. Но стоит только поделить на ноль, как вместо делителя (равного нулю) будет подставлена единица.

Не всегда и всюду нужна проверка, поэтому разработчики предоставили нам средство быстрого отключения функции проверки для заданных программных блоков — атрибут {attribute 'no_check'}. Его необходимо добавить в первую строку области объявления переменных, до строк PROGRAM, FUNCTION_BLOCK или FUNCTION. Тем более, что использование автопроверки вызывает дополнительную нагрузку на процессор.


Оценка производительности


Справочная система предупреждает о дополнительной нагрузке на ПЛК при использовании функций проверки деления (а также функций проверки на выход за пределы диапазона или проверки адреса указателя). Давайте измерим эту нагрузку. Для этого я написал специальный тест производительности:

FOR c := 1 TO 1000000 DO
    a := 12 / b;
END_FOR

Управлять нагрузкой будем с помощью количества циклов FOR: от 100 000 до 1 000 000 (столбец A). Непосредственно нагрузку подсмотрим в закладке Online раздела SYSTEM. Всего необходимо рассмотреть три различных случая:
  1. Без контроля деления на ноль, выставлен атрибут "no_check" — зеленый столбец B.
  2. С включенным контролем деления на ноль — желтый столбец C.
  3. С включенным контролем деления на ноль и, через установку переменной b := 0, имитируем деление на ноль в каждой итерации цикла — красный столбец D. Предполагается максимальная нагрузка.
И сразу результат. По вертикальной оси гистограммы отражена нагрузка на процессор ПЛК в процентах (80% — заданный мною потолок для TwinCAT):


воскресенье, 4 февраля 2018 г.

Электропочта, твиттер и телеграмм

С этого момента транслировать посты из блога в твиттер будут роботы. Для людей открыт живой Телеграмм (Telegram Messenger) со свежайшими новостями и постами. Смартфоны сейчас есть у всех, осталось выяснить, как удобнее доставлять полезную информацию. Найти канал можно по названию Got TwinCAT или пройдя по ссылке https://t.me/gotwincat. Прямо сейчас там ожидается:
  • описание новых постов в блоге, с авторскими комментариями (ссылка прилагается);
  • новости, которые не разворачиваются до размера поста в блоге или просто некогда;
  • ссылки на интересные посты в других блогах;
  • что-то еще, о чем я могу оперативно написать, не оттягивая послание до формата статьи в блог.

По прежнему можно комментировать посты блога. Если не хочется открытого диалога или вы нигде не зарегистрированы и не можете (не хотите) войти — анонимно задайте вопрос из формы "Задать вопрос..." в правой колонке блога. Когда вы указываете адрес электропочты — я могу отправить ответ.

Твиттер все-еще работает, но интересного там уже не будет.

суббота, 3 февраля 2018 г.

Spectre и Meltdown

После очередного обновления Windows была пропатчена на предмет уязвимостей Spectre/Meltdown. Им, если кратко, подвержены практически все современные процессоры(!) Именно процессоры, а точнее, их супер-современная архитектура. И пока все еще мутно относительно продукции AMD, с Intel и частично ARM-ом уже многое понятно.

На самом деле, все не так страшно, как трубили СМИ, да и производители операционных систем уже подсуетились и наставили заплат, зато просела производительность ЦПУ, но там интереснее другое. Нам интереснее другое, а дома решайте самостоятельно — отключать или нет.
Детектив о трех частях про уязвимости можно прочитать там: Meltdown // Spectre // часть третью ищите самостоятельно, там кажется про андроид-телефоны, что совершенно неинтересно для мира Total WINdows Control etc, но интересно для расширения кругозора.

Кстати, разобраться как вообще работают эти уязвимости — полезный перк в понимании работы компьютерного "железа".

Основная проблема в заплатках которые выкатили разработчики Windows. Так как уязвимость заключается в самой архитектуре процессора, то и патч задевает что-то важное на очень низком уровне операционной системы, а TwinCAT работает как раз там: на уровне драйверов и системных вызовов.

Кратко: проблема касается только рабочего режима 64-разрядного рантайма TwinCAT 3 на полных версиях Windows. Как только вы попытаетесь запустить локальный 64-разрядный рантайм TwinCAT 3 — тут же отхватите упаковку глюков, багов и синих экранов.

Проблема не касается:
  • Windows CE (Compact).
  • 32-x разрядных версий полноценной Windows.
  • В режиме конфигурирования (синий значок).
  • В инженерных версиях независимо от разрядности.

В общем, как обычно — отключаем этот патч и ждем очередную версию TwinCAT, где обещают решить проблему совместимости. Не нужно отключать обновления операционной системы, оставьте все как есть, просто отключите патч — об этом читайте дальше.

ЗЫ: Проблемы с запуском действительно проявляются. Проверено на живых человеках (мы бережем природу и животных).


Отключаем эти обновления совсем


Beckhoff Security Incident Team предлагает нам скачать официальный патч из спасательного набора WinPE_DeploySkript (257Мб). Распакуйте его куда-нибудь и запустите \WinPE_DeployScript\WinPeX64_Basic\media\patch.cmd от имени Администратора (правой кнопкой → запустить во имя Администратора).

Перезагрузитесь.

Аналогичное можете сделать вручную через редактор реестра и погуглив пару-тройку минут. Если же синий экран смерти все-таки настиг вас, создайте загрузочную флэшку с помощью \WinPE_DeployScript\CreatePE.bat и загружайтесь с нее. Далее скрипт patch.cmd, про который было выше.

среда, 27 сентября 2017 г.

Расширение UNION

Давно хотел попинать полумертвое существо UNION, которому вообще сложно найти красивое и практичное применение, но тут в тему появилась статья Стефана Хеннекена о возможности расширять UNION через наследование в TwinCAT 3.

Итак, тип UNION — это как бы структура, но не она. Все ее элементы занимают одно адресное пространство, поэтому записывая данные в один элемент, мы перезаписываем целиком или частично данные остальных элементов. В структурах эти элементы называются полями, здесь же сложно использовать термин "поле" потому что адресное поле по сути — одно единственное, а переменных несколько и они могут быть разного типа и разного размера — что, впрочем, тоже является одной из ключевых фишек этого типа данных.

Можно пытаться убедить не применять UNION, что он устарел и больше не нужен, но мы по прежнему одной ногой в эмбедед, где все-таки приходится иногда экономить память (первое применение), использовать трюки с преобразованием типов данных (второе применение) и где только-только появилось ООП (привет CoDeSys 3 и TwinCAT 3).


Расчленение данных


TYPE ST_Word:
STRUCT
    Lo : BYTE;    (* младший байт *)
    Hi : BYTE;    (* старший байт *)
END_STRUCT
END_TYPE

TYPE U_Word:
UNION
    Bytes : ST_Word;
    Value : WORD;
END_UNION
END_TYPE

Объявив переменную как UNION, мы получили структуру, внутри которой два элемента (Bytes и Value) хранятся в одном адресном пространстве. Записывая, что-либо в переменную Value мы также записываем эти данные и в Bytes. Верно и обратное — записывая данные в поля структуры Bytes : ST_WORD мы одновременно заполняем данными переменную Value.

Это очень похоже на синонимы (ALIAS), но с разными типами данных, и на самом деле никакой одновременности записи в разные переменные здесь нет — просто данные лежат в одном месте и разные пересекающиеся части этого места называются по разному. К сожалению, построчная запись в объявлении UNION часто сбивает с толку разработчиков, и они забывают, что данные переменных хранятся в ячейках памяти, и контроллер работает с ячейками памяти, а не с какими-то там именами человеческих переменных.

PROGRAM MAIN
VAR
    yourWord : U_Word;
    hi       : BYTE;
    lo       : BYTE;
END_VAR

yourWord.Value := 16#AABB;
hi := yourWord.Bytes.Hi;    // == 16#AA
lo := yourWord.Bytes.Lo;    // == 16#BB

Записываем в поле Value 16-разрядное число, которое накладыватся на 16-разрядную структуру Bytes : ST_WORD, содержащую два байтовых поля. Таким образом записанное значение разбивается на две однобайтных части: старший байт и младший байт. И никаких битовых операций для доступа к байтам WORD.

В TwinCAT 3 появился механизм наследования, который мы можем применить к UNION:

TYPE U_Word EXTENDS ST_Word:
UNION
    Value : WORD;
END_UNION
END_TYPE

Код становится лаконичнее, так как отпала необходимость в указании промежуточной структуры Bytes:

PROGRAM MAIN

yourWord.Value := 16#AABB;
hi := yourWord.Hi;    // == 16#AA
lo := yourWord.Lo;    // == 16#BB


Одно поле

Картинка лучше тысячи слов. Возьмем скарпель указателей и пройдемся по плитке памяти:



Адреса элементов Value, Lo и адрес в pYourWord (это указатель на UNION) совпадают, так как они расположены в начале области памяти выделенной под UNION. Указатель конечно же не расположен, а ссылается, но нас интересуют адреса, а не механизм работы. Теперь сравните адреса ячеек Lo и Hi (pYourWord_Lo и pYourWord_Hi, соответственно). Они различаются ровно на один байт, так как каждая из них занимает ровно один байт, а расположены они последовательно друг за другом.

Если этого недостаточно, то вот вам код:

PROGRAM MAIN
VAR
    oneWord         : WORD;
    yourWord        : U_WORD;
    
    pYourWord       : ULINT;
    pYourWord_Value : PVOID;
    pYourWord_Lo    : LWORD;
    pYourWord_Hi    : LWORD;

    wordLo          : BYTE;
    wordHi          : BYTE;
END_VAR

pYourWord       := ADR(yourWord);
pYourWord_Value := ADR(yourWord.Value);
pYourWord_Lo    := ADR(yourWord.Lo);
pYourWord_Hi    := ADR(yourWord.Hi);

oneWord         := yourWord.Value;

MEMCPY(
    ADR(wordLo), (* <-- *) pYourWord_Lo,
    SIZEOF(wordLo));

MEMCPY(
    ADR(wordHi), (* <-- *) pYourWord_Hi,
    SIZEOF(wordHi));

Вместо типов LWORD и ULINT здесь лучше использовать POINTER TO U_WORD и POINTER TO BYTE, но мне хотелось убедиться, что указатели теперь 64-х разрядные и что для хранения адресов подходят 64-х разрядные типы: LWORD, ULINT, PVOID. Последний, кстати, как и обещали в TwinCAT 3 стал 64-х разрядным.
PVOID — это синоним для UDINT в TwinCAT 2 (32-х разрядные адреса) или для ULINT в TwinCAT 3 (64-х разрядные адреса). Всегда используйте его как универсальное хранилище адреса, так как независимо от версии TwinCAT, вы всегда получите переменную с правильным типом данных. Вот еще один пример правильного использования ALIAS.
Заодно посмотрите на смертельно опасную функцию MEMCPY, позволяющую писать куда угодно в память.


Другие применения UNION


Экономим память — храним данные разных типов в одном месте. Главное, точно знать какие данные сохранены в текущий момент времени и вовремя их перезагружать.


Реинтерпретация типа данных


Мы хотим считать, что вот тот тип данных сейчас не REAL, а DWORD. Например, чтобы без лишних преобразований пересылать его через Modbus:

TYPE U_Real :
UNION
    Re : REAL;
    Dw : DWORD;
END_UNION
END_TYPE

Для работы используем поле Re, а для отправки данных Dw. И никакого преобразования данных, все происходит автоматически.


Variant


Или когда мы не знаем какой тип данных будет использован во время работы программы. Этот же прием можно использовать для создания псевдо-полиморфизма в TwinCAT 2.

Сначала готовим болванку для хранения данных разного типа:

TYPE U_VarObject :
UNION
    AsInteger  : INT;
    AsFloat    : REAL;
    AsDouble   : LREAL;
    LikeString : STRING;
END_UNION
END_TYPE

Затем описываем (перечисляем) доступные типы данных:

TYPE E_VarType :
(
    Integer,
    Float,
    Double,
    String255
);
END_TYPE

Упаковываем все это в структуру:

TYPE ST_Variant :
STRUCT
    TypeIs : E_VarType;
    Value  : U_VarObject;
END_STRUCT
END_TYPE


Работает как-то так:

PROGRAM MAIN
VAR
    xVar    : ST_Variant;

    Counter : INT;
    Text    : STRING;
END_VAR

CASE xVar.TypeIs OF
    E_VarType.Integer:
        Counter := xVar.Value.AsInteger;

    E_VarType.Float:
        ;

    E_VarType.Double:
        ;

    E_VarType.String255:
        Text := xVar.Value.LikeString;
END_CASE


Синонимы


Очень похоже на вычленение данных, но будем использовать по принципу ALIAS:

TYPE ST_Vector3R:
STRUCT
    X : REAL; 
    Y : REAL; 
    Z : REAL; 
END_STRUCT
END_TYPE

TYPE U_Vector3R EXTENDS ST_Vector3R:
UNION
    E : ARRAY [1..3] OF REAL;
END_UNION
END_TYPE


Теперь координаты вектора доступны для нас как по именам, так и по индексам:

PROGRAM MAIN
VAR
    Vec : U_Vector3R;
    i   : UINT;
END_VAR

FOR i := 1 TO 3 DO
    Vec[i] := i * 100;
END_FOR

Vec.Y := 0.0;

пятница, 7 июля 2017 г.

Вебинар. Введение в K-Bus и терминалы серии KL3xxx

Тема анонса была запутанной и заранее было непонятно — о чем же все-таки нам расскажут. В итоге все это вылилось в краткое описание модулей K-bus и почему они больше не нужны. Есть вероятность, что это было краткое введение и когда-нибудь будет более подробное, так как тема интересна хотя бы тем, что еще много живого оборудования из предыдущего поколения.

Вещал Мартин Подрушек (Martin Podrouschek): Beckhoff K-Bus and analog inputs. Introduction of KL3xxx terminals.

Изображение: Beckhoff Automation

В 70-х годах прошлого века (ого!) была принята трехступенчатая система: ПЛК ↔ много-много-модулей-ввода-вывода ↔ сенсоры/актуаторы (исполнительные механизмы). В 95-м году Бекхофф предложил собрать все это в одном устройстве "интеллектуальная система терминалов шины" (intelligent bus terminal system) и в итоге получился Profibus bus coupler BK3000:

Система предусматривает как минимум две линии питания: одна линия питает логику коплера и логику терминалов (модулей расширения), а вторая линия предназначена для питания входов/выходов терминалов. Выхода  в принципе могут потреблять значительный ток или вообще сгореть, но логика питается по другой линии, поэтому она сможет пожаловаться коплеру о неприятностях в силовой части. Если питания не хватает или нужно развязать часть модулей по питанию — можно добавить в линейку специальный модуль подпитки и потенциальной развязки.

Кроме коплера как обычного транслятора пакетов данных (коплеры BKxxxx) были разработаны программируемые коплеры с мозгами — серия BCxxxx.


Внутренности и способности


Условно можно разделить систему на два уровня передачи данных: уровень полевой шины до коплера и уровень периферийных устройств — внутренняя шина (K-bus), то есть внутренняя шина между коплером и терминалами. Из-за такой сепарации возникает проблема диагностики, так как отсутствует непосредственная прямая связь между внешней полевой шиной и терминалами.

Внутри терминала содержится набор регистров, содержащих настройки модуля и, соответственно, позволяющие менять поведение модуля. Часть регистров хранится в ОЗУ, часть в ПЗУ, а часть в EEPROM. В результате, часть регистров жестко прописаны производителем и не меняются, какие-то можно изменять, а какие-то сбрасываются и восстанавливаются при каждом новом включении. Некоторые вообще защищены паролем.

Система поддерживает максимум 256 дискретных устройств ввода/вывода или 128 аналоговых. Так как после 64 терминалов обязательно необходим модуль подпитки шины, то в итоге максимально возможное число модулей сокращается до 250.

Каждое устройство может поддерживать до четырех каналов ввода/вывода. Каждый канал — это всего-лишь 3 байта данных. Если нужно больше каналов, то придется мультиплексировать, дробить время обработки, сокращая другие каналы. Хорошая новость — все это решается на уровне коплера. Также ограничено суммарное количество регистров на канал — 64 регистра. Если нужно больше, то вводят вторую страницу регистров.

Типичное время цикла коплера 1..2 миллисекунды.

При включении система проходит самотестирование. Модули поступают аналогично, а затем сравнивается последовательность или структура модулей на коплере. Если происходит ошибка, то ее код выставляется на полевую шину, а модули зажигают аварийный индикаторы.

Внутри память модуля разбита на две области: область входов и область выходов. Каждая из этих областей в свою очередь разбита на область байтовой памяти (регистры данных для аналоговых входов/выходов) и область битовой памяти (дискретные входа/выхода).


Доступ к регистрам


Способ первый: через специальную платную программу KS2000 и специальный кабель Serial/USB KS2000-Z2-USB.

Изображение: Beckhoff Automation

Способ второй: программный, через ПЛК Бекхофф по шине с помощью функциональных блоков библиотеки Tc2_Coupler.lib.

Способ третий: инженерный в режиме FreeRun или Run доступ к регистрам через TwinCAT System Manager: тыкаем правой кнопкой в коплер в дереве конфигурации и выбираем Register Access...

В любом случае система не настолько стандартизирована, как более новая, построенная на EtherCAT, поэтому следует внимательно изучить документации. Всегда есть несколько выходов, той или иной степени прямости.


Сравнение и выводы


K-Bus (1995 год прошлого века) ][ EtherCAT, E-Bus (2003 год текущего века):
  • Идентификация устройства: нет ][ производитель и код продукта.
  • Стоимость: сложный и дорогой ][ простой и дешевле.
  • Передача данных: меньше 10 мегабит ][ быстрая, до 100 мегабит.
    * на самом деле мегабод, ну, да ладно.
  • Синхронизация: нет ][ жесткая, распределенные часы с погрешностью меньше 100 наносекунд.
  • Операционный образ данных: 4x12 байт ][ теоретически можно до 65 килобайт, практически используется 8 килобайт.
  • Диагностика: двух-шаговая ][ непосредственная.
  • Доступ: опосредованный через регистры ][ непосредственный CAN-через-ADS (CoE).

Вывод я вам лучше нарисую:

вторник, 4 июля 2017 г.

Вебинар. Что нового в сборке №4022

Некоторые новинки сборки TwinCAT №4022 я перечислял в стратегиях развития, но это было не точно и на уровне слухов. 27 июня прошел официальный вебинар TwinCAT 3.1 | New features in Build 4022, на котором Йозеф Папенфот (Dr. Josef Papenfort) подробно рассказал о новых и значимых функциях введенных в систему.
Изображение: Beckhoff Automation

Все новые фишки более-менее перечислены на официальном сайте, но это скорее официальный бюллетень, нам же будут интересны некоторые подробности. Для начала, скачиваем с официального сайта Бекхофф новую сборку 3.1.4022.0: TwinCAT 3.1 – eXtended Automation Engineering (XAE). Один год — один новый релиз, но в этом билде только небольшие исправления и обновления.

Доктор официально подтвердил, что начиная со сборки 4020.x начата поддержка Windows 10 Redstone 4020.x. Поддержка Redstone 2 ожидается в середине 2017 года. Печальная же новость, что начиная с билда 4022 заканчивается поддержка всеми любимой Windows XP и WES 2009 (Windows Embedded Standart), то есть 4022 на них работать уже не будет.


Архив проектов


Что было удобно в TwinCAT 2, так это два файла на целый проект: программа в .pro-файле и конфигурация в .tsm. В то же время это было не удобно для систем контроля версий, так как файлы были бинарные — зато почтой отправлять удобно. Чтобы как-то скомпенсировать эти проблемы, был введен новый формат решения (solution, солюшен) — архив .tnzip. Внутри — это обычный архив ZIP, только расширение подлиннее.

Новый формат позволяет сжимать один или несколько проектов TwinCAT 3 в единственный файл архива. И сразу же отправить по почте: для этого есть специальный пункт меню. Впоследствии такой архив можно открыть как обычное решение (solution), то есть вот прямо сразу из архива, ничего не распаковывая.


Я поархивировал немного и выяснил, что в архиве хранятся только проекты TwinCAT. Все посторонние проекты, относительно TwinCAT (например, проект на C#), система игнорирует и в архив не включает. Зато архивы реально сжатые, сравните на картинке ниже размер "до" (Size) и размер "в" (Packe...)


Полезные мелочи


Постепенно улучшается редактор кода: добавлено раздельное масштабирование шрифтов в редакторе кода ST и окне объявления переменных. Для улучшения восприятия, появились специальные атрибуты создающие схлопывающиеся регионы — это кусок кода между специальными метками {region}

{region 'название для региона'}

... кусок кода

{endregion}

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

В CFC-рисовалке блоков появилось автодополнение кода (IntelliSense), а в менеджере библиотек — специальная иконка, подсказывающая когда плейсхолдер куда-то там переместился и теперь указывает на другую версию библиотеки.


Переменные ввода-вывода


Переменные ввода типа AT %I* (location variables) теперь недоступны для изменения из кода: bInputVar := NOT bInputVar — запрещено на уровне компилятора и при сборке проекта приведет к ошибке компиляции. Зато теперь, начиная с билда 4022, эти переменные могут получать начальное значение: bInputVar AT %I* : INT := 123;

Из-за таких вот нововведений, функция __ISVALIDREF теперь работает только со ссылками. Про ссылки и указатели уже было, но там не было про эту функцию, которая подсказывает существует ссылка или нет:

<результат типа BOOL> := __ISVALIDREF(переменная типа REFERENCE TO <тип данных>);

TRUE — ссылка рабочая, FALSE — ссылка нулевая, подробнее читайте в справочной системе.

Соответственно REFERENCE TO на переменные AT %I* теперь тоже запрещены, так как изменение этих переменных запрещено и такая попытка будет пресекаться ошибкой компиляции.


ADS через MQTT


Поддержка реализована как .dll модуль для Mosquitto Broker. Уже есть как 32-х разрядная так и 64-разрядная версии. Модуль поставляется бесплатно, вместе со стандартным установщиком и лежит в каталоге AdsApi:


Проект-одиночка


Начиная с этого момента ПЛК-программа и конфигурация TwinCAT — могут быть двумя разными, раздельными проектами: один проект будет содержать только программный проект (программу технологического процесса, TwinCAT PLC Project), а второй, будет содержать только конфигурацию системы (TwinCAT XAE Project).

Не обязательно так делать всегда, просто учтите, что они теперь так могут, и в сложных проектах это будет просто спасение утопающему в строках кода, но вы все еще можете засунуть в конфигурацию ПЛК-программу. Просто теперь есть выбор:


Проекты связываются разработчиком друг с другом через .tmc-файл. Причем в одну конфигурацию можно засунуть несколько программных проектов, а один программный проект можно использовать в нескольких разных конфигураций: не скопировать одну программу в несколько конфигураций, а просто прилинковать проект посредством .tmc-файла.

При таком подходе, изменяя ПЛК-проект в одном месте, мы будем изменять его во всех конфигурациях одновременно. Главной при этом не забыть пересобрать ПЛК-проект: Build → Build Solution (F7), и активировать конфигурацию в TwinCAT-XAE-проекте: Activate Configuration.

Такой принцип чем-то схож с использованием библиотек, но только пишем мы не библиотеку (Empty PLC Project), а обычную программу (Standart PLC Project).



Символьный маппинг


Теперь можно обновлять ПЛК-проект независимо от конфигурации, а новый маппинг переменных несовместим со старым. Переменные привязываются друг к другу с помощью символьной информации (грубо говоря — по именам). Прошивка контроллера должна быть новой и поддерживать.

Список системных типов данных переехал из закладок SYSTEM напрямую в дерево проекта и получил отдельную ветку с неожиданным названием Type System. Теперь туда с помощью заклинания Add New Item... и такого-то .tmc файла можно добавить распределенные типы данных (Shared Types), которые затем можно оттранслировать через EAP по TCP/IP сетям. Или через системы контроля версий, или вообще по любым каналам. Электронная почта все еще работает.


TwinSAFE


На диаграммах отображается состояние TwinSAFE-группы: в случае ошибки вы увидите толстую красную рамку, и вообще появились другие цвета, отражающие состояние входов/выходов и другие состояния. Плюс мелочи в редактировании схем безопасности: копи-паста функциональных блоков или псевдонимов (Alias Devices), разбивка на подкаталоги для псевдонимов устройств.


Книга жалоб и предложений


В XAE встроили специальный пункт меню для отправки письма сразу в тех. поддержку Бекхофф. При нажатии, появляется готовая форма, которую нужно заполнить. Причем ведет форма себя очень странно, так как доступна только из TwinCAT Measurement Project (это который про рисование графиков) и кликнуть нужно обязательно по ветке проекта Scope XY Project.



Монитор ADS


Бесплатный, но качается и устанавливается отдельно с FTP-сайта Бекхофф: TF6010-ADS-Monitor. После установки будет лежать здесь: C:\TwinCAT\Functions\TF6010-ADS-Monitor\Viewer\TcAmsAdsViewer.exe

С помощью монитора можно смотреть на пакеты ADS, иногда отправляя свои собственные. Аналогичное можно получить из WireShark, только здесь фильтры настраивать не нужно.



Установка


В остальном билд №4022 установился без проблем на Windows 10 Home. Если собираетесь запускать контроллер на локальной машине разработчика (ноутбук на котором программируете), то после установки запустите от имени "Администратора" батник: C:\TwinCAT\3.1\System\win8settick.bat и перезагрузите компьютер.