March 29, 2016

Как найти контроллер и добавить запись в роутер

Чего не хватает в стандартных библиотеках TwinCAT.Ads API, так это поиска родственных душ контроллеров в Ethernet-подсети и удаленной работы с удаленными же таблицами роутеров. В System Manager и XAE эта функция реализована через "секретный" протокол и следовательно закрыт от пытливого ума разработчика. Почему именно так решил сумрачный немецкий гений — не известно, но видимо по причине дополнительной безопасности.

Тем не менее разработчики по всему миру засучили рукава и взялись оголенными руками за акулу-провод (WireShark). В результате, в той или иной степени подробности, они выпотрошили этот тайный протокол, но так и не поделилось друг с другом результатами. А зря — сэкономили бы пару другую часов рабочего времени.

Если вы с трудом понимаете о чем были предыдущие абзацы, а их становится все больше и больше, то вспомните про кнопки Choose Target, Search (Ethernet) и Broadcast Search. Именно про их программную реализацию будут следующие абзацы текста.
Отдельные разрозненные куски протокола поиска контроллеров можно найти в LinkedIn и на GitHub, но окончательная работоспособная реализация появилась только в библиотеках AdsRemote и AdsClient.


Broadcast Search


Широковещательный поиск контроллеров реализован через UDP-протокол. В справочной системе этот факт отражен в виде рекомендации по настройке файервола Windows: для нормальной работы TwinCAT рекомендуется сразу открыть два порта — TCP:48898 и UDP:48899. Второй — как раз отвечает за широковещательную рассылку поисковых пакетов. Соответственно, работает только в локальной подсети.

Все устройства получившие пакет должны откликнуться в соответствующем формате. В библиотеке AdsRemote эта функция реализована в методе BroadcastSearchAsync статического класса Ads.Remote.Router.AmsRouter. Метод к тому же асинхронный (await/async), что удобно для разработки пользовательских интерфейсов.

На входе метод получает два параметра: широковещательный адрес подсети и таймаут времени поиска. Если со вторым параметром ничего сложного нет — для быстрой локальной сети задаем 100 миллисекунд, для более медленной подсети интервал можно увеличивать до десятков секунд; первый же параметр выглядит совершенно непонятным для людей не знакомых с функционированием сетей Ethernet. Поэтому существует очередной костыль — вспомогательный статический класс IPHelper.

IPHelper позволяет получить список IP-адресов локального компьютера, за это отвечает свойство Localhosts, которое возвращает список локальных адресов только для Ethernet и WiFi. Если этого мало — можно воспользоваться методом FilteredLocalhosts который на вход принимает список сетевых интерфейсов.

После выбора требуемого локального адреса можно опять-таки с помощью IPHelper'а вытащить широковещательный адрес. За это чудо отвечает метод GetBroadcastAddress.

Посмотреть как эта машинерия работает в совокупности можно в подпроекте CxFinder.



В итоге, мы все равно получим список контроллеров List<RemotePlcInfo> из которого можем подчерпнуть: имя контроллера, IP-адрес, Ams NetId, версию TwinCAT и версию операционной системы с комментариями. Этого вполне достаточно для добавления записи в локальный и удаленный роутеры.

Если IP-адрес ПЛК известен заранее — мы можем запросить у него аналогичное описание. В этом нам помогает статический, асинхронный метод GetRemotePlcInfoAsync.


Локальная таблица AMS-роутера


Домашнее задание для зависших в начале 2000-х годов — исследовать ветку реестра: HKEY_LOCAL_MACHINE\SOFTWARE\Beckhoff\TwinCAT\Remote\

Для ребят помоложе и уже успевших соскочить с 32-разрядных операционок, то же самое, но с приставкой Wow: HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Beckhoff\TwinCAT\Remote

Также не помешает ознакомиться со статьей про WOW6432Node и API-функции RegOpenKeyEx / RegEnumKeyEx. На десерт можно освежить память про роутеры AMS и роутеры ADS.


Add Route


Чтобы добавить запись в таблицу AMS-роутера ПЛК необходимо создать экземпляр класса PLC, затем через его поле Router получить непосредственно доступ к таблице AMS-роутера. Добавление записи происходит с помощью метода AddRecordAsync:

public async Task<bool> AddRecordAsync(
    IPAddress localhost,
    IPAddress remoteHost,
    AmsNetId localAmsNetId,
    string localIpName = null,
    string name = null,
    string login = "Administrator",
    string password = "1",
    bool isTemporaryRoute = false,
    int timeout = 10000,
    int adsUdpPort = Request.DEFAULT_UDP_PORT)
  • localIpName может быть как именем локального компьютера, так и IP-адресом.
  • name — это название записи в таблице роутера. По умолчанию, оно берется из Environment.MachineName.
  • login и password — это учетная запись пользователя на контроллере. У пользователя должно быть достаточно прав на работу с записями роутера. Обычно, это администратор.
  • isTemporaryRoute — позволяет создать временный, одноразовый роутинг который чаще всего никому не нужен.

No comments

Post a Comment

Note: Only a member of this blog may post a comment.