Не все сервисы TwinCAT описаны в документации. В старых исходниках библиотеки AdsClient, в файле AdsSpecial.cs, есть любопытная функция public string GetTargetDesc(). Описание функции гласит: "Get an xml description of the plc...". Посмотрим, какое именно описание отдаст нам контроллер.
Начнем с системного сервиса, порт номер R3_CTRLPROG = 10000. Официальное описание списка функций заканчивается номером 600 (см. таблицу System Service Index Groups). Мы же прочитаем индекс 700 (0x02BChex). Настраиваем роутинг и начинаем читать. Код C# программы:
using System; | |
using System.Linq; | |
using System.Text; | |
using System.Xml.Linq; | |
using TwinCAT.Ads; // v4.4.0.0 | |
namespace AdsReadSystemConfig | |
{ | |
class Program | |
{ | |
const string TARGET_AMS = "127.0.0.1.1.1"; | |
const uint READDEVDESCRIPTION_IDX = 0x0000_02bc; | |
const uint READDEVDESCRIPTION_OFF = 0x0000_0001; | |
static void Main() | |
{ | |
var client = new TcAdsClient(); | |
var ams = new AmsAddress(TARGET_AMS, AmsPort.R3_CTRLPROG); | |
client.Connect(ams); | |
// length of the plc's xml description | |
int length = (int)client.ReadAny(READDEVDESCRIPTION_IDX, READDEVDESCRIPTION_OFF, typeof(int)); | |
var adsStream = new AdsStream(length); | |
client.Read(READDEVDESCRIPTION_IDX, READDEVDESCRIPTION_OFF, adsStream); | |
string description = Encoding.UTF8.GetString(adsStream.ToArray()).TrimEnd('\0'); | |
var xdoc = XDocument.Parse(description); | |
var elements = xdoc.Descendants(); | |
Console.WriteLine(xdoc); | |
Console.WriteLine(); | |
// looking for the name of PLC's OS | |
var osName = elements.FirstOrDefault(x => x.Name == "OsName")?.Value ?? "<Unknown>"; | |
Console.WriteLine("Press [Enter] to close..."); | |
Console.ReadLine(); | |
} | |
} | |
} |
Первый запрос отправляем с параметром typeof(int). Где-то внутри библиотеки это транслируется в параметр команды равный 4 — это длина типа данных int в байтах. В ответ, запрос вернет длину XML текста с описанием устройства. Зная размер, мы отправляем второй запрос в тот же порт-индекс-смещение, но в качестве параметра передаем длину описания, полученного на предыдущем шаге. Результат парсим. С помощью LINQ ищем и вытаскиваем интересующие нас поля описания.
Контроллер CX9020 вернул такой XML:
<TcTargetDesc> | |
<TargetType>CX9020-M510-CE</TargetType> | |
<TargetVersion> | |
<Version>3</Version> | |
<Revision>1</Revision> | |
<Build>4024</Build> | |
</TargetVersion> | |
<TargetFeatures> | |
<NetId>5.59.222.141.1.1</NetId> | |
</TargetFeatures> | |
<Hardware> | |
<Model>CX9020-M510</Model> | |
<SerialNo>79307</SerialNo> | |
<CPUVersion>2.9</CPUVersion> | |
<Date>15.10.18</Date> | |
<CPUArchitecture>5</CPUArchitecture> | |
</Hardware> | |
<OsImage> | |
<ImageDevice>CX9020</ImageDevice> | |
<ImageVersion>6.08g</ImageVersion> | |
<ImageLevel>HPS</ImageLevel> | |
<OsName>Windows CE</OsName> | |
<OsVersion>7.0</OsVersion> | |
</OsImage> | |
</TcTargetDesc> |
Сравним описания от CX9020 (Win CE) и ноутбука (Windows 10). Чтобы отследить различия, сохраним XML в отдельный файл: xdoc.Save( "cx9020.xml" ); и воспользуемся программой WinMerge:
TС/BSD
Новая, перспективная и все еще недоступная операционная система выдает следующее описание:
<TcTargetDesc> | |
<TargetType>TC/BSD-OS</TargetType> | |
<TargetVersion> | |
<Version>3</Version> | |
<Revision>1</Revision> | |
<Build>4024</Build> | |
</TargetVersion> | |
<TargetFeatures> | |
<NetId>39.159.94.42.1.1</NetId> | |
</TargetFeatures> | |
<Hardware> | |
<Model>0</Model> | |
<SerialNo>0</SerialNo> | |
<CPUVersion>0.0</CPUVersion> | |
<Date>0.0.00</Date> | |
<CPUArchitecture>9</CPUArchitecture> | |
</Hardware> | |
<OsImage> | |
<ImageVersion>12.1.20200716091138,1</ImageVersion> | |
<OsName>TC/BSD</OsName> | |
<OsVersion>12.1</OsVersion> | |
</OsImage> | |
</TcTargetDesc> |
Пропали элементы `ImageDevice`, `ImageLevel`. Значение `CPUArchitecture` стало более осмысленным, но что такое 9 все еще непонятно.
Тоже сервисы
Можно найти еще несколько интересных сервисов, если копнуть глубже. Для раскопок пригодится какой-нибудь HEX-вьюер (VSCode hexdump) и следующая строка: File.WriteAllBytes( $"idx_{READDEVDESCRIPTION_IDX}.bin", adsStream.ToArray() ); // Начинайте копать.
Индекс 701 выдаст список всех сетевых интерфейсов доступных на устройстве. IP-адреса, маски подсети и что-то еще. Формат неизвестен, но можно разобраться самостоятельно. Копайте.
Из любопытного, для TC/BSD сервис возвращает название сетевого интерфейса в
юникс стиле — `em0`.
А для Windows возвращает GUID: "{7D8FDCBA-6250-8DFF-4089-AB0845B12EDC} Qualcomm Atheros AR5BWB222 Wireless
Network Adapter 192.168.2.177 255.255.255.0".
Индекс 702 отдает имя целевой машины: PC-8E5B1A, CX-3F5BC9... Строка заканчивается '\0', не забывайте про .TrimEnd('\0'); Продолжайте копать.
No comments
Post a Comment
Note: Only a member of this blog may post a comment.