PDA

Просмотр полной версии : Проблема с sysExecute5



Dmitry Dedkov
10.06.2025, 11:22
Коллеги, добрый день. Случилась такая вот проблема. Перестал работать парсинг JSON через ФБ sysExecute5. Хотел добавить пару изменений, разобрался с проблемой кириллицы (для тех, кто вдруг столкнется с этой проблемой: jq в любом случае выводит строку в кодировке UTF-8 в терминал, в cds 3.5.7.30 string имеет кодировку ascii, wstring - UCS-2, по этой причине в string вы не сможете записать кириллицу, а для wstring вам надо будет перекодировать строку с помощью iconv в UTF-16 сразу, либо другими способами, из библиотеки owen string utils функция CP1251_TO_UNICODE у меня не сработала), но не могу этого проверить тк вывода по сути нету. Из изменений в коде считай никаких, только изменение самой команды, отправляемой в терминал, изменения размера массива, в который потом данные записываются (добавилось 9 сигналов), изменился тип массива выходных данных (со string на wstring), и файл конфига новый (название файла поменял). В чем проблема: при старте программы ФБ sysExecute5 встает в положение xExecute := true, но после xBusy остается false и не меняет своего значения. Откат к предыдущей версии тоже перестал работать.
Код программы ниже (упрощенная версия тк пытался сам понять, в чем проблема, тут только запись в буфер данных, без их распределения, поведение одинаковое в обоих случаях):


PROGRAM INICIATE_SIGNALS_2
VAR
GetDataFromJSON: BOOL := TRUE;
sPathToFile: STRING := 'home/root/CODESYS/cfg_2.json';
fbJSONParser: CmpSysExec.sysExecute5;
sCommand: STRING(255);
i: INT := 0;
wsDITemp: ARRAY [0..c_iDISize] OF WSTRING(512);
wsDOTemp: ARRAY [0..c_iDOSize] OF WSTRING(512);
wsIDOTemp: ARRAY [0..c_iIDOSize] OF WSTRING(512);
wsAITemp: ARRAY [0..c_iAISize] OF WSTRING(512);
wsTIMERSTemp: ARRAY [0..c_iTimersSize] OF WSTRING(512);
eJSONFIeld: JSON_FIELD := JSON_FIELD.discret_inputs;
END_VAR
VAR CONSTANT
c_iDISize: INT := 264;
c_iDOSize: INT := 146;
c_iIDOSize: INT := 141;
c_iAISize: INT := 40;
c_iTimersSize: INT := 21;
c_sCommand: STRING(255) := 'jq -c $'.#SIGNALS#[] $' #PATH_TO_FILE# | iconv -f UTF-8 -t UTF-16BE';
//c_sCommand: STRING(255) := 'jq -c $'.#SIGNALS#[] $' #PATH_TO_FILE#';
END_VAR

IF GetDataFromJSON THEN
CASE eJSONFIeld OF
JSON_FIELD.discret_inputs:

sCommand := OSU.ReplaceSubstring(sSource := c_sCommand,
sWhatToReplace := '#SIGNALS#',
sReplaceWith := 'di_signals');

sCommand := OSU.ReplaceSubstring(sSource := sCommand,
sWhatToReplace := '#PATH_TO_FILE#',
sReplaceWith := sPathToFile);

fbJSONParser(xExecute := TRUE,
pCommand := ADR(sCommand),
szCommand := SIZEOF(sCommand),
pOutput := ADR(wsDITemp[i]),
szOutput := SIZEOF(wsDITemp[i])
);

IF fbJSONParser.xBusy AND wsDITemp[i] <> "" AND i < c_iDISize THEN
i := i+1;
END_IF

IF fbJSONParser.xDone THEN
fbJSONParser(xExecute := FALSE);
i := 0;
eJSONFIeld := JSON_FIELD.NULL;
END_IF
JSON_FIELD.NULL:
PLC_SIGNALS.init_to_spk := TRUE;
GetDataFromJSON := FALSE;
END_CASE
END_IF

Евгений Кислов
10.06.2025, 15:57
Добрый день.

Навскидку


szCommand := SIZEOF(sCommand),

Выглядит сомнительно. Логичнее было бы использовать LEN вместо SIZEOF.

Но я не уверен, что это единственная причина наблюдаемого вами поведения.

Лучше напишите на support@owen.ru и приложите к письму ссылку на наиболее простую версию вашего проекта, в которой удается повторить данную проблему.


Откат к предыдущей версии тоже перестал работать.

Если вы делали это без перезагрузки ПЛК - это логично. При некорректном использовании SysExecute начинаются проблемы с содержимым оперативной памяти.

aaaSashaMGGU
10.06.2025, 16:41
Мой код по отправке почты через CmpSysExec.SysExecute5
Всё давно работает, ничего не ломается
Кириллица поддержана
Вдруг поможет


//Файл '/home/SendMail.txt' должен выглядеть как-то так:
(*-------------------------------------------------------------------------------------------------------------------
From: fff@ggggg.ru
To: ggggn@hhhhh.ru, hgjhgj@hgjhgjhgj.ru
Subject: Тема письма
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="BOUNDARY"

--BOUNDARY
Content-Type: text/plain; charset=UTF-8

Здесь идёт текстовка самого письма, строка №1
Здесь идёт текстовка самого письма, строка №2

--BOUNDARY
Content-Type: text/plain; charset=UTF-8
Content-Disposition: attachment; filename*=UTF-8''%D1%84%D0%B0%D0%B9%D0%BB.txt
Content-Transfer-Encoding: UTF-8

Здесь идёт текстовка вложенного файла, строка №1
Здесь идёт текстовка вложенного файла, строка №2
Здесь идёт текстовка вложенного файла, строка №3
--BOUNDARY
-------------------------------------------------------------------------------------------------------------------*)
FUNCTION_BLOCK My_CURL_EMAIL (*ФБ отправки электронной почты*)

//Входы-Выходы
VAR_IN_OUT
xExecute : BOOL; //Запуск
Mutex : BOOL; //Mutex для блокировки
END_VAR

//Входы
VAR_INPUT
sMailTo : WSTRING(255); //Список получателей
sTopic : WSTRING(255); //Тема письма
sMessage : WSTRING(131071); //Текстовка письма
sFileName : WSTRING(255); //Имя файла для вложения
sTextForFile : WSTRING(131071); //Содержимое файла для вложения
END_VAR

//Выходы
VAR_OUTPUT
xDone : BOOL; //Признак конца работы
xBusy : BOOL; //Признак занятости
xError : BOOL; //Признак ошибки
END_VAR

//Внутренние параметры
VAR
//R-триггер для фиксации запуска работы ФБ
fbRiseEdge : R_TRIG;

//Тексты для "/home/SendEmail.txt"
sMailFile : WSTRING(131071); //Текст файла для отправки письма "/home/SendEmail.txt"
sMailFile_UTF8 : STRING(131071); //Текст файла для отправки письма "/home/SendEmail.txt" в кодировке UTF8

//ФБ для отправки команд на контроллерную консоль
fbSe5: CmpSysExec.SysExecute5;

//Немножко магии для работы с файлом
pResult : POINTER TO SysFile.SysTypes.RTS_IEC_RESULT;
hFile : POINTER TO SysFile.SysTypes.RTS_IEC_HANDLE;

//Вспомогательный текст
TempText : WSTRING(1023);

//Реальная команда отправки на контроллерную консоль
sCommand_Real: STRING(2047) := '';

//Массив для парсинга списка получателей
MassivParsing : ARRAY[1..255] OF WSTRING(255); //Сам массив
sCommandParsing : WSTRING(255); //Итоговая строка
sCommandParsing_UTF8 : STRING(255); //Итоговая строка в UTF8

//Ненужный ответ от блока отправки на консоль //Но удалять его нельзя, т.к., без него блок не работает
asOutput: STRING(2047);

//Переменная цикла
i : INT; //Сама переменная
i_Max : DINT; //Максимальный индекс массива для парсинга списка получателей

//Определение реального конца работы
Mutex_TON : TON; //Таймер
Mutex_TON_PrVkl : BOOL; //Признак активации таймера
END_VAR

//Константы
VAR CONSTANT
//Команда отправки на контроллерную консоль
sCommand: STRING(2047) := 'curl --mail-from "qqq@qqq.ru" #MAILRCPT# --url "smtp://444.44.4.4:25" -u ggg@hhhh.ru:fdglfdmnjnfdlg --upload-file "/home/SendEmail.txt"';
END_VAR


//Проверяем признак запуска
fbRiseEdge(CLK := (xExecute AND NOT Mutex));

//Если появился признак запуска...
IF fbRiseEdge.Q THEN

//Парсим список получателей
i_Max := OSU.WSplitStringByToken(ADR(sMailTo), TO_UINT(WLen(sMailTo)), ", ", ADR(MassivParsing), SIZEOF(MassivParsing[1]), 255); //Парсим строку

//Цикл для формирования итоговой строки после парсинга списка получателей
sCommandParsing := "";
FOR i := 1 TO DINT_TO_INT(i_Max) DO
sCommandParsing := WCONCAT04(sCommandParsing, " --mail-rcpt $"", MassivParsing[i], "$"");
END_FOR

//Итоговая строка после парсинга списка получателей в правильной кодировке UTF8
STU.ConvertUTF16toUTF8(ADR(sCommandParsing), ADR(sCommandParsing_UTF8), SIZEOF(sCommandParsing_UTF8), FALSE);
sCommand_Real := OSU.ReplaceSubstring(sCommand, '#MAILRCPT#', sCommandParsing_UTF8);

//Формируем текстовку письма, где будут лежать все его параметры
//Обнуляем
Memutils.MemSet (ADR(sMailFile), 0, SIZEOF(sMailFile));
Memutils.MemSet (ADR(sMailFile_UTF8), 0, SIZEOF(sMailFile_UTF8));
sMailFile := "";
sMailFile_UTF8 := '';

//Пишем строки от кого и кому
TempText := WCONCAT03("From: opa@zaoshr.ru$r$nTo: ", sMailTo, "$r$nSubject: ");
SuperAddWString(ADR(sMailFile), ADR(TempText), TO_DWORD(SIZEOF(sMailFile)));

//Тема письма
SuperAddWString(ADR(sMailFile), ADR(sTopic), TO_DWORD(SIZEOF(sMailFile)));

//Пишем строки
TempText := "$r$nMIME-Version: 1.0$r$nContent-Type: multipart/mixed; boundary=$"BOUNDARY$"$r$n$r$n--BOUNDARY$r$nContent-Type: text/plain; charset=UTF-8$r$n$r$n";
SuperAddWString(ADR(sMailFile), ADR(TempText), TO_DWORD(SIZEOF(sMailFile)));

//Текстовка письма
SuperAddWString(ADR(sMailFile), ADR(sMessage), TO_DWORD(SIZEOF(sMailFile)));

//Пишем строки
TempText := "$r$n$r$n--BOUNDARY$r$nContent-Type: text/plain; charset=UTF-8$r$nContent-Disposition: attachment; filename*=UTF-8''";
SuperAddWString(ADR(sMailFile), ADR(TempText), TO_DWORD(SIZEOF(sMailFile)));

//Имя файла в кодировке "URL Escape Codes"
TempText := Convert_To_URL_Escape_Code(sFileName);
SuperAddWString(ADR(sMailFile), ADR(TempText), TO_DWORD(SIZEOF(sMailFile)));

//Пишем строки
TempText := "$r$nContent-Transfer-Encoding: UTF-8$r$n$r$n";
SuperAddWString(ADR(sMailFile), ADR(TempText), TO_DWORD(SIZEOF(sMailFile)));

//Содержимое файла для вложения
SuperAddWString(ADR(sMailFile), ADR(sTextForFile), TO_DWORD(SIZEOF(sMailFile)));

//Пишем строки
TempText := "$r$n--BOUNDARY";
SuperAddWString(ADR(sMailFile), ADR(TempText), TO_DWORD(SIZEOF(sMailFile)));

//Конвертер в UTF8
STU.ConvertUTF16toUTF8(ADR(sMailFile), ADR(sMailFile_UTF8), TO_DWORD(SIZEOF(sMailFile_UTF8)), FALSE);

//Пишем файл "/home/SendEmail.txt" перед отправкой самого письма
hFile := SysFile.SysFileOpen('/home/SendEmail.txt', SysFile.ACCESS_MODE.AM_WRITE, pResult);
SysFile.SysFileWrite(hFile, ADR(sMailFile_UTF8), TO_UDINT(StrLenA(ADR(sMailFile_UTF8))), pResult); //Пишем
SysFile.SysFileClose(hFile);

//Сброс команды запуска и активация блокировки по Mutex
xExecute := FALSE;
Mutex := TRUE;
Mutex_TON_PrVkl := TRUE;
END_IF

//Блок отправки команды через контроллерную консоль
fbSe5
(
xExecute := fbRiseEdge.Q,
pCommand := ADR(sCommand_Real),
szCommand := TO_DWORD(STU.StrLenA(ADR(sCommand_Real))),
pOutput := ADR(asOutput), //Ненужный ответ //Но удалять его нельзя, т.к., без него блок не работает
szOutput := SIZEOF(asOutput), //Ненужный ответ //Но удалять его нельзя, т.к., без него блок не работает
xDone => xDone,
xBusy => xBusy,
xError => xError
);

//Таймер конца работы, проверка на разблокировку и сама разблокировка
Mutex_TON(IN := Mutex_TON_PrVkl, PT := T#10S);
IF Mutex_TON_PrVkl AND (xDone OR xError OR Mutex_TON.Q) THEN
Mutex_TON_PrVkl := FALSE;
Mutex := FALSE;
END_IF

Dmitry Dedkov
10.06.2025, 16:58
По определенным причинам весь проект не смогу скинуть, только ту часть, которая затрагивает конкретно инициализацию из JSON файла. В целом то, что я уже продемонстрировал, является самой простой версией проекта, в которой у меня данная проблема возникла.

При некорректном использовании SysExecute начинаются проблемы с содержимым оперативной памяти.
Это я заметил давно, но забываю постоянно, когда прошлую версию инициализации делал

Dmitry Dedkov
11.06.2025, 08:46
Написал на почту, вчера уже никак не мог, не было под рукой проекта

Dmitry Dedkov
11.06.2025, 09:55
Я так и сделал, проблема сохранилась. Этот проект и отправил по почте в поддержку

Dmitry Dedkov
11.06.2025, 10:48
Файл отправил, команда в терминале выполняется без проблем. В Putty и при подключении по ssh из убунту все хорошо, но вот когда использую встроенный терминал в winscp результат как раз похож на тот, что дает вывод. На счет поврежден или нет попробую проверить.
842898429084291

Dmitry Dedkov
11.06.2025, 14:47
А возможно ли такое, что у меня повредились системные библиотеки? А то у меня даже R_TRIG работает не корректно (попробовал вернуться к примеру из документа и при смене CLK := xExecute с false на true выход Q у триггера у меня не меняет своего значения)

kondor3000
11.06.2025, 14:58
А возможно ли такое, что у меня повредились системные библиотеки? А то у меня даже R_TRIG работает не корректно (попробовал вернуться к примеру из документа и при смене CLK := xExecute с false на true выход Q у триггера у меня не меняет своего значения)

Скорее всего у вас данная программа, без задачи, а значит не исполняется.
Вы же ни одного скрина не дали и проект не выложили. А выход R_TRIG можно и не увидеть глазами, если что.
А так же после изменений надо делать Очистить всё, компилировать всё, периодически.

Dmitry Dedkov
11.06.2025, 15:12
Программа добавлена в задачу MainTask, все она исполняется. У меня получилось получить код ошибки, но где его посмотреть (код ошибки 1). До этого его не выводило

aaaSashaMGGU
11.06.2025, 15:31
А возможно ли такое, что у меня повредились системные библиотеки? А то у меня даже R_TRIG работает не корректно (попробовал вернуться к примеру из документа и при смене CLK := xExecute с false на true выход Q у триггера у меня не меняет своего значения)

Однажды у меня было что-то подобное. Оказалось, что данный PRG находился одновременно в двух разных тасках - и всё сходило с ума

Dmitry Dedkov
16.06.2025, 09:20
Обновление: причиной такого поведения оказалась утилита iconv, из-за нее почему-то и не хотели читаться данные из командной строки