Тем не менее разработчики по всему миру засучили рукава и взялись оголенными руками за акулу-провод (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.
Если 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.