Источник
Сначала нужно определиться, что именно будем читать. Для начала я не стал
брать последовательные порты или другие устройства, а решил воспользоваться
псевдоустройством... поэтому будем читать случайные числа из
/dev/urandom. Это не совсем
то, что мне хотелось бы проверить, но пока обойдемся этим. Как вариант можно
считать память операционной системы через
/dev/mem. Сервис TwinCAT под
BSD запускается с root доступом, поэтому проблем возникнуть не должно.
Прочитанное из устройства, можно просто сохранить в массив, но мы сделаем два
дела сразу — кроме чтения устройства, сохраним результат в файл, лежащий на
другом ПЛК. Итого: два ПЛК (один с TC/BSD, другой с Windows), соединены
обычной локальной сетью Ethernet. На одном ПЛК читаем случайные числа из
файла-псевдоустройства, а результат сохраняем на другой ПЛК в настоящий файл.
Код
Код настолько простой, что смотреть особенно не на что: ряд обычных файловых
операций. Именно в этом заключается преимущество подхода "всё есть файл".
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
PROGRAM MAIN | |
VAR | |
state: INT; | |
buf: byte; | |
tmpStr: STRING; | |
hDev, hResFile: UINT; | |
RUN: BOOL; | |
Open: FB_FileOpen := (ePath := PATH_GENERIC); | |
Read: FB_FileRead := (sNetId := ''); | |
Write: FB_FileWrite := (sNetId := sRemoteNetId); | |
Close: FB_FileClose; | |
END_VAR | |
VAR CONSTANT | |
sDevPath: STRING := '/dev/urandom'; | |
sResPath: STRING := 'c:\dev\urandom.txt'; | |
sRemoteNetId: STRING := '172.17.176.49.1.1'; | |
END_VAR | |
CASE state OF | |
0: | |
IF RUN THEN | |
Open (bExecute := FALSE); | |
Write(bExecute := FALSE); | |
Read (bExecute := FALSE); | |
Close(bExecute := FALSE); | |
state := 100; | |
END_IF | |
100: | |
Open( | |
bExecute := TRUE, | |
sNetId := '', | |
nMode := FOPEN_MODEREAD OR FOPEN_MODEBINARY, | |
sPathName := sDevPath ); | |
IF NOT Open.bBusy THEN | |
hDev := Open.hFile; | |
Open(bExecute := false); | |
state := 110; | |
END_IF | |
110: | |
Open( | |
bExecute := TRUE, | |
sNetId := sRemoteNetId, | |
nMode := FOPEN_MODEWRITE OR FOPEN_MODEBINARY, | |
sPathName := sResPath ); | |
IF NOT Open.bBusy THEN | |
hResFile := Open.hFile; | |
Open(bExecute := false); | |
state := 200; | |
END_IF | |
200: | |
Read( | |
bExecute := TRUE, | |
hFile := hDev, | |
pReadBuff := ADR(buf), | |
cbReadLen := SIZEOF(buf) ); | |
IF NOT Read.bBusy THEN | |
Read(bExecute := false); | |
state := SEL(Read.cbRead < 1, INT#210, INT#300); | |
END_IF | |
210: | |
tmpStr := CONCAT(BYTE_TO_STRING(buf), '$r$n'); | |
Write( | |
bExecute := TRUE, | |
hFile := hResFile, | |
pWriteBuff := ADR(tmpStr), | |
cbWriteLen := INT_TO_UDINT(LEN(tmpStr)) ); | |
IF NOT Write.bBusy THEN | |
Write(bExecute := FALSE); | |
state := SEL(RUN, INT#300, INT#200); | |
END_IF | |
300: | |
Close( | |
bExecute := TRUE, | |
sNetId := '', | |
hFile := hDev ); | |
IF NOT Close.bBusy THEN | |
Close(bExecute := FALSE); | |
state := 310; | |
END_IF | |
310: | |
Close( | |
bExecute := TRUE, | |
sNetId := sRemoteNetId, | |
hFile := hResFile ); | |
IF NOT Close.bBusy THEN | |
Close(bExecute := FALSE); | |
RUN := FALSE; | |
state := 0; | |
END_IF | |
END_CASE | |
END_PROGRAM |
Открывать несколько файлов можно с помощью одного и того же ФБ. Главное делать
это последовательно: сначала один, затем другой. Основная задача получить
хендлер файла для дальнейших файловых операций. Нам нужно получить два
хэндлера, от двух файлов, заданных следующими
путями: sDevPath — задает путь к источнику
'/dev/urandom' и sResPath — путь к файлу с
результатом 'c:\dev\random.txt'. Сразу видно — где Юникс, а где Виндовс
(подсказка, обратить внимание на /слэши/ в путях). В финале добавим в
константы VAR CONSTANT адрес удаленного ПЛК:
sRemoteNetId = '172.17.176.49.1.1'.
Будем читать бинарные данные, то есть числа в виде потока байтов. Поэтому при
открытии файла необходимо установить флаг бинарного режима чтения nMode := ... FOPEN_MODEBINARY. Кстати, читать можно и блоками по несколько килобайт за раз, но в данном
случае так проще сохранять числа в виде текста.
В остальном все очень просто: открываем, читаем, обрабатываем-конвертируем и
сохраняем. Преобразование значения байта как числа из диапазона 0..255 в
текстовый вид делается в строке:
tmpStr := CONCAT(BYTE_TO_STRING(buf), '$r$n');
... а в конце добавляем символ '$r$n' — перевод каретки CRLF, таким
образом выстраивая числа в столбик. Позднее, я засуну эти случайные числа в
Эксель для анализа.
Набрав достаточное количество чисел, стоит вежливо остановить процесс через
принудительную установку переменной RUN в значение FALSE. Резкая
остановка работы программы, чревато тем, что на приемной стороне файл с
результатом останется открытым и занятым: ни прочитать, ни удалить. Если такое
произойдет, необходимо на приемной стороне вручную перезапустить системный
сервис TwinCAT System Service или выполнить из командной строки с
привелегиями администратора:
powershell -command "Restart-Service TcSysSrv -Force". Заметьте, какой уровень доверия возникает на двух ПЛК, между которыми
налажен роутинг. Это к вопросу о безопасности и отказоустойчивости по обе
стороны сетевого кабеля.
Анализируем случайные числа
В Юникс системах есть несколько генераторов случайных чисел. Они отличаются
надежностью, скоростью, блокировками, чем-либо еще, поэтому их несколько.
Анализировать можно даже случайные числа, тем более, что они псевдослучайные.
Например, можно посмотреть как числа распределены и устраивает ли это
раработчика, технолога или просто любопытного человека.
Интересно посмотреть как распределяется нагрузка по ядрам. Всего виртуальной
машине выделены два ядра, но не факт, что ядра настоящие: возможно, что и
просто два потока (хост с гипертредингом). Зато видно как нагружен
TcSystemService — системный сервис TwinCAT:
Вместо диспетчера задач здесь используется утилита top или
можно установить более красивый htop:
doas pkg install htop. На
картинке выше используется htop.
No comments
Post a Comment
Note: Only a member of this blog may post a comment.