Вход

Просмотр полной версии : Component Manager удаление компонента



Спорягин Кирилл
13.08.2025, 18:36
Вечер добрый, форумчане!

Внимательно изучил документ "Работа c логами в CODESYS V3 (https://owen.ru/forum/showthread.php?t=28167&page=4&p=272260&viewfull=1#post272260)" (автор Евгений Кислов) и сопутствующую информацию (документацию Кодесис по библиотекам CmpLog и Component Manager).

Наткнулся на следующую ситуацию.
Если вызываешь функцию CMRemoveComponent для уже удаленного компонента (т.е. сначала создал компонент, затем его удалил и затем еще раз пытаешься), то происходит исключение.
Что в общем логично. Не логично только, то что нигде никаких записей об этом не остается! Более того после этого действия подключиться к панели из среды разработки не получается. Помогает только или перезагрузка по питанию или перезагрузка кодесис из веб-конфигуратора (ПЛК -> Настройки -> "Перезапустить CODESYS").

Для аналогии попробовал как будет вести себя система при делении на 0. В этом случае также вылетает по исключению, но и в журнале веб-конфигуратора (ПЛК -> "Файлы журналов") и в журнале из под CODESYS видно исключение. Более того, если после этого подключаться из среды, то тебя выбрасывает на строчку, где произошла ошибка (см. фото).
85287
85288

Для возможности повторить эксперимент выкладываю проекта (архив проекта грузить не стал, так как проект стандартный, добавлены только системные библиотеки - CmpLog, ComponentManager, CmpErrors).
Среда разработки - Codesys V3.5 SP17 Patch 3 (32 bit).
СПК - СПК М01 (3.5.17.31).

Собственно, вопросы:
1. Почему никаких следов о причина возникновения ошибки?
2. Как в целом грамотно обрабатывать исключения в Codesys V3.5?
3. Как понимать, что компонент уже удален? Только самому следить за этим фактом? Тут нужно пояснение. После вызова CMRemoveComponent ни указатель не обнуляется, ни номер компонента, которые были созданы функцией CMAddComponent2.

Спасибо.

Евгений Кислов
13.08.2025, 18:59
Добрый день.

0. Ситуация, которую вы описываете - это баг.

85291

1. Последствия некоторых ошибок настолько разрушительны, что другие компоненты (например, логгер) уже могут просто не отработать.
2. Для начала следует определить критерии "грамотности". Можете связаться со мной через телеграм, чтобы подискутировать на эту тему.
3.


Как понимать, что компонент уже удален?

Возможно (не проверял), CMGetComponentByName поможет.


После вызова CMRemoveComponent ни указатель не обнуляется, ни номер компонента, которые были созданы функцией CMAddComponent2.

И не должны - это же ваши переменные.
Можете обнулить их сами, если вызов CMRemoveComponent вернул ERR_OR.

Спорягин Кирилл
14.08.2025, 11:51
Евгений, спасибо за ответ.

В целом все понятно.


2. Для начала следует определить критерии "грамотности". Можете связаться со мной через телеграм, чтобы подискутировать на эту тему.
Вы лучше статью напишите на эту тему, а мы (форумчане) прочтем!

Спорягин Кирилл
06.02.2026, 16:40
Доброго времени суток, уважаемые форумчане.
Решил попробовать работу механизма TRY_CATCH при ошибке с повторным удалением компонента журнала.

Результаты показаны на прикрепленном видео. Тестовую программу прикрепляю (без архива, так как используются только стандартные библиотеки).

Краткие комментарии.
Как было описано выше в сообщениях, если повторно удалять компонент, то система вылетает по исключению, на панели СПК загорается черный экран, так как будто бы в панели
нет приложения. Для подключения из среды разработки нужно перезагрузить панель по питанию или из веб-конфигуратора. Этот эксперимент можно провести с тестовым проектом (TestComponentManager2), если галочка "Использовать TRY_CATCH" снята.

Если галочка установлена, то попытка удаления компонента происходит в секции __TRY.
Полный код PLC_PRG представлен ниже:

Cntr := Cntr + 1;

IF AddCmp THEN
AddCmp := FALSE;
AddCntr := AddCntr + 1;
pCmp := Component_Manager.CMAddComponent2(Name,16#0305111E ,ADR(udiCmpID),ADR(dwResult));
END_IF

IF DelCmp THEN
DelCmp := FALSE;
DelCntr := DelCntr + 1;
LogAdd2(LOG_STD_LOGGER, udiCmpID,CmpLog.LogClass.LOG_WARNING, CmpErrors.Errors.ERR_FAILED, 1,'Deleting Component');

IF NOT UseTC THEN
dwResult := Component_Manager.CMRemoveComponent(pCmp);
ELSE
__TRY
dwResult := Component_Manager.CMRemoveComponent(pCmp);
__CATCH(Exec)
strTemp := concat('IN CATCH SECTION! Deleting Component ERROR:',UDINT_TO_STRING(Exec));
LogAdd2(LOG_STD_LOGGER, udiCmpID,CmpLog.LogClass.LOG_WARNING,
CmpErrors.Errors.ERR_FAILED, 1, strTemp);
__ENDTRY
END_IF
END_IF

IF TestMes THEN
TestMes := FALSE;
TestCntr := TestCntr + 1;
LogAdd2(LOG_STD_LOGGER, udiCmpID,CmpLog.LogClass.LOG_WARNING, CmpErrors.Errors.ERR_FAILED, 1,'Test Message');
END_IF

IF Test0Div THEN
Test0Div := FALSE;

IF NOT UseTC THEN
rTest := rTest/rTest;
ELSE
__TRY
rTest := rTest/rTest;
__CATCH(Exec)
strTemp := concat('IN CATCH SECTION! Divide ERROR:',UDINT_TO_STRING(Exec));
LogAdd2(LOG_STD_LOGGER, udiCmpID,CmpLog.LogClass.LOG_WARNING,
CmpErrors.Errors.ERR_FAILED, 1, strTemp);
__ENDTRY
END_IF
END_IF

НО!
Использование механизма TRY_CATCH не помогает.

В результате панель все равно "зависает". Причем зависание стабильно происходит при отключении среды разработки от панели (т.е. при команде Онлайн->Отключение). Хотя в представленном видео среда сама "отвалилась" от панели (без моей команды) и сразу как это произошло, панель зависла!!!

Спорягин Кирилл
06.02.2026, 18:02
Заметил, что в секции CATCH используется идентификатор компонента, который удаляется в секции TRY.
Попробовал, вариант, где в секции CATCH сообщения пишутся по нулевому идентификатору (в этом случае сообщения регистрируются как сообщения от компонента "СМ"):

IF DelCmp THEN
DelCmp := FALSE;
DelCntr := DelCntr + 1;
LogAdd2(LOG_STD_LOGGER, udiCmpID,CmpLog.LogClass.LOG_WARNING, CmpErrors.Errors.ERR_FAILED, 1,'Deleting Component');

IF NOT UseTC THEN
dwResult := Component_Manager.CMRemoveComponent(pCmp);
ELSE
__TRY
dwResult := Component_Manager.CMRemoveComponent(pCmp);
__CATCH(Exec)
strTemp := concat('IN CATCH SECTION! Deleting Component ERROR:',UDINT_TO_STRING(Exec));
LogAdd2(LOG_STD_LOGGER, udiBaseID,CmpLog.LogClass.LOG_WARNING,
CmpErrors.Errors.ERR_FAILED, 1, strTemp);
__ENDTRY
END_IF
END_IF

В коде выше udiBaseID = 0.

Но поведение системы не изменилось, т.е. так же "зависает".