Showing posts with label reference to. Show all posts
Showing posts with label reference to. Show all posts

July 4, 2017

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

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

Все новые фишки более-менее перечислены на официальном сайте, но это скорее официальный бюллетень, нам же будут интересны некоторые подробности. Для начала, скачиваем с официального сайта Бекхофф новую сборку 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 и перезагрузите компьютер.

July 5, 2016

Ссылки и указатели

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


Указатели


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

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

Массивы — это тоже указатели, только завуалированные; и это была первая попытка человечества перестать отстреливать себе конечности, так как для массивов есть проверка на выход за границы массива.
Указатель на массив повторно разрешает членовредительство.

Чтобы подобраться ближе к данным, на которые указывает указатель, используют операцию ^  -разыменование указателя. Указатель от этого не портится и не разыменовывается, мы просто записываем данные в ту ячейку, на которую указывает указатель.

PROGRAM MAIN
VAR
    pt_a    : POINTER TO INT;
    pt_pt_a : POINTER TO POINTER TO INT;
    fbTest  : FB_Test;
    pt_fb   : POINTER TO FB_Test;

// [...]

a       := 123;
pt_a    := ADR(a);             // pt_a указывает на 'a'
pt_pt_a := ADR(pt_a);          // pt_pt_a указывает на pt_a который указывает на 'a'
pt_a^   := 67;                 // 'a' теперь равно 67
pt_fb   := ADR(fbTest);

fbTest(inp := a, in_out := a);
pt_fb^(inp := a, in_out := a); // разыменование указателя на ФБ и запуск ФБ


Ссылки


REFERENCE TO — ссылаться можно только на данные (и структуры, они тоже данные) и указатели (получим второе имя для указателя). Ссылки с арифметикой не дружат, поэтому они надежнее: выйти за границы приличия не получится.

Можно считать, что ссылка это та же самая переменная только с другим именем: ячейка памяти одна — имени два (или три, или четыре, сколько пожелаете).

PROGRAM MAIN
VAR
    a         : INT;
    ref_a     : REFERENCE TO INT;
    ref_pt_a  : REFERENCE TO POINTER TO INT;
    pt_ref_a  : POINTER TO INT;

// [...]

a         :=    123;
ref_a     REF=  a;
pt_ref_a  :=    ADR(ref_a); // указатель на ссылку
ref_a     :=    67;         // 'a' теперь равно 67
ref_a     REF=  0;          // ссылка больше ни на что не указывает
pt_ref_a^ :=    44;         // 'a' теперь равно 44


Для получения ссылки используется оператор REF=. Слитно три буквы и знак равно, все без пробелов. Это и есть оператор получения ссылки. На картинке ниже видно как переменная и ссылка на нее принимают одинаковое значение = 67:



Стоит обратить внимание на указатель pt_ref_a, который хоть и пытается указывать на ссылку ref_a, но мы то уже знаем, что ref_a это всего-лишь второе название для переменной 'a'. Поэтому в итоге указатель указывает на переменную 'a' типа INT.



После присваивания ссылке нуля (в предпоследней строке), указатель pt_ref_a по прежнему указывает на переменную 'a', хотя ссылка ref_a уже никуда не ссылается. Это подтверждает что мы просто удаляем "второе" название переменной 'а', в то время как сама переменная остается на месте (соответственно, сохраняется и указатель на нее).


Зачем ссылки?


Предположим, мы хотим передать в ФБ переменную, которую ФБ обработает, а затем запишет в эту переменную новое значение (так часто поступают со структурами, когда хотят заполнить их интересными данными или нулями). Проще всего это можно сделать передав указатель на переменную, но тогда возникает опасность, что внутри себя ФБ воспользуется арифметикой указателей и сдвинет указатель настолько, что в итоге обратится к запрещенному и обрушит всю систему. Что делать?

Давайте воспользуемся ссылкой, ведь для нее арифметика не работает! Все правильно, и за нас это уже сделали.

Любой ФБ, кроме входных параметров VAR_INPUT и VAR_OUTPUT имеет набор VAR_IN_OUT. Если первые два принимают входные данные по значению, то последний IN_OUT принимает входной параметр как ссылку. Изменяя ее значение внутри ФБ, мы сможем изменять значение переменной снаружи ФБ, ведь ссылка это второе имя переменной.

FUNCTION_BLOCK FB_Test
VAR_INPUT
    inp    : INT;

VAR_OUTPUT
    out    : INT;

VAR_IN_OUT
    in_out : INT;

// [...]

inp    := 44;
out    := 55;
in_out    := 77;


Запускаем и смотрим в отладчике на результат:



ФБ изнутри изменил значение внешней переменной 'a', сменив ее значение на = 77. Изменение входного параметра inp внутри ФБ на = 44, никак не повлияло на значение переменной 'a', так как он принимает параметр по значению (просто создает локальную копию значения).


Массивы переменной длины


Мы разрабатываем ФБ, который как-то там должен изменять содержимое массива (например, заполнять латинскими лорем-ипсумами или нулями). Внимание, вопрос — как передавать в ФБ массивы разной длины?

FUNCTION_BLOCK POUPIUPOW
VAR_IN_OUT
    VarArray : ARRAY [*] OF INT;
END_VAR
VAR
    start    : DINT;
    end      : DINT;
END_VAR

// [...]

start := LOWER_BOUND(VarArray, 1);
end   := UPPER_BOUND(VarArray, 1);


Работает только для VAR_IN_OUT параметров (иначе как бы мы влияли на внешние к ФБ массивы).
Совместимо с третьей редакцией стандарта МЭК.
Для определения габаритов или просто начала и конца массива используются функции LOWER_BOUND и UPPER_BOUND. Второй параметр этих функций — это номер размерности: 1 — получить длину одномерного массива; 1..2 — длину строки или кол-во столбцов для двумерного массива; 1..3 — длина строки, столбца или глубины для 3D массива.