PDA

Просмотр полной версии : Перегрузка функций в CODESYS



RomeoVar
12.07.2021, 18:01
Пока не имею возможности создать тему в разделе "ПЛК (среда программирования CODESYS V3.5)" поэтому задам вопрос здесь.
Есть в компиляторе на ST возможность перегрузки функций ( а еще лучше шаблоны). В онлайн справке ничего по этой теме не нашел. Но возникла необходимость
Если кто чего знает по теме - отзовитесь
Заранее признателен

Евгений Кислов
12.07.2021, 18:17
Пока не имею возможности создать тему в разделе "ПЛК (среда программирования CODESYS V3.5)" поэтому задам вопрос здесь.
Есть в компиляторе на ST возможность перегрузки функций ( а еще лучше шаблоны). В онлайн справке ничего по этой теме не нашел. Но возникла необходимость
Если кто чего знает по теме - отзовитесь
Заранее признателен

Опишите задачу, которую вы пытаетесь решить.

RomeoVar
12.07.2021, 19:20
Опишите задачу, которую вы пытаетесь решить.

Инициализация структур. Есть три массива - INT, WORD, FLOAT. Данные из этих массивов сохраняются в 3 отдельных файла. Реализовал один (пока) FB которому передаю имя файла, ссылку на массив и размер массива.
Соответственно в первом случае в FB для ссылки на массив я объявлю входную переменную:


VAR_INPUT
pInt: POINTER TO INT;
END_VAR


во втором:


VAR_INPUT
pInt: POINTER TO WORD;
END_VAR


и в последнем


VAR_INPUT
pInt: POINTER TO FLOAT;
END_VAR


СОответственно мне нужно реализовать 3 FB с разными именами SAVE_INT(FB), SAVE_WORD(FB), SAVE_FLOAT(FB)

А с перегрузкой функции я бы мог реализовать 3 FB с одинаковыми именами (например - SAVE(FB)).

А с шаблонами я бы вообще запилил один FB. Но это так...

Если бы можно было объявить POINTER без квалификатора - проблема была-бы решена. Но этого сделать (по-моему) нельзя.
ВОт и возник у меня вопрос.

Евгений Кислов
12.07.2021, 19:23
https://help.codesys.com/webapp/_cds_datatype_any;product=codesys;version=3.5.17.0
https://help.codesys.com/webapp/type_class;product=LibDevSummary;version=3.5.17.0

RomeoVar
12.07.2021, 19:28
https://help.codesys.com/webapp/_cds_datatype_any;product=codesys;version=3.5.17.0
https://help.codesys.com/webapp/type_class;product=LibDevSummary;version=3.5.17.0

Это только для встроенных типов данных (как я понял)? Если я реализовал собственную структуру - я уже не могу использовать ANY?

Евгений Кислов
12.07.2021, 19:37
Это только для встроенных типов данных (как я понял)? Если я реализовал собственную структуру - я уже не могу использовать ANY?

Не можете.
Но можно сделать функцию с сигнатурой типа (pstStructData, szStructData, eStructData) - соответственно, (указатель на экземпляр нужной структуры, размер структуры в байтах, тип структуры).

указатель на экземпляр нужной структуры - POINTER TO BYTE
Под указатель можно подложить что угодно.

RomeoVar
12.07.2021, 19:40
А вот интересно как реализован например блок
fbFileRead(xExecute:=TRUE, hFile:=hFile, pBuffer:=ADR(MConfigTmp), szBuffer:=SIZEOF(MConfigTmp));
До меня дошло я же ему передаю тупо любой указатель?


Read (FB; Prefix filrd)

FUNCTION_BLOCK Read EXTENDS CBM.ETrigToA


This function block reads the file, which was previously opened via ”FILE.Open”. If less characters can be read than specified in ”szBuffer”, the function block returns an active ”xDone” and indicates the current number of characters in ”szSize”. The size of the target memory structure for the bytes to be read and the number of bytes to be read will not be checked.

If the stability of the pointer on the data structures and their contents cannot be guaranteed in case of an online change, an online change must be avoided.
InOut:






Scope

Name

Type

Comment


Input hFile CAA.HANDLE File handle
pBuffer CAA.PVOID Target address for the first byte to be read; can be retrieved via operator ADR
szBuffer CAA.SIZE Maximum number of bytes to be read; can be retrieved via operator sizeof
Output eError ERROR Local library error ID (0: no error; 5101: time out)
szSize CAA.SIZE Current number of successfully read bytes; this value is already valid before xDone has been set



Вот выдержка. Тут используется встроенный тип данных CAA.PVOID. Это мне должно подойти
Попробую так


FUNCTION_BLOCK InitCfgCheck
VAR_INPUT
sFileName : STRING;
pBuffer : FILE.CAA.PVOID;
szBuffer : FILE.CAA.SIZE;

END_VAR
VAR_OUTPUT

Евгений Кислов
12.07.2021, 19:41
А вот интересно как реализован например блок
fbFileRead(xExecute:=TRUE, hFile:=hFile, pBuffer:=ADR(MConfigTmp), szBuffer:=SIZEOF(MConfigTmp));
До меня дошло я же ему передаю тупо любой указатель?

Повторю - под указатель можно подложить что угодно.*
И это не особенность этого блока, это везде так будет работать.

* - за редким исключением (например, нельзя подложить константу)

RomeoVar
12.07.2021, 20:00
Ладно. Исхитрился. Добавил проверок, но втолкнул все в один FB все-таки проще.

RomeoVar
13.07.2021, 00:44
Ничего пока не получилось.
А работает в CODESYS динамическое выделение памяти?
Я нашел библиотеку CMM (Codesys Memory Manager) Только там справка никакая.
Всего один FB - LinearMemoryManager и много методов. В частности есть Alloc, Free. И (как будто) конструктор - FB_Init
Только при попытке использования этого FB компилятор мне выдает "не найдено подходящего конструктора FB_Init для данного функционального блока"
А что я сделал не правильно я так и не понял. Поэтому от выделения динамической памяти я пока отказался
Но все-же - может кто скажет вообще можно работать с динамической памятью из CODESYS и как.
СОвсем на просторах интернета ничего не нашел

Евгений Кислов
13.07.2021, 04:42
https://help.codesys.com/webapp/_cds_operator_new;product=codesys;version=3.5.17.0
https://help.codesys.com/webapp/fb_factory;product=LibDevSummary;version=3.5.17.0

RomeoVar
13.07.2021, 09:04
В целом разобрался, нужно потестировать но ПЛК пока далеко. Пытаюсь на эмуляторе прогнать, однако при вызове FB FILE.GetSize сразу вываливается ошибка ASM_CREATEJOB_FAILED 5113 Job creation of AsyncManager failed
Эмулятор не поддерживает работу с файлами?

Вы уж не сердитесь. Просто много вопросов возникает по ходу "пЪессы". Платформа пока новая, в процессе изучения

Евгений Кислов
13.07.2021, 09:11
В целом разобрался, нужно потестировать но ПЛК пока далеко. Пытаюсь на эмуляторе прогнать, однако при вызове FB FILE.GetSize сразу вываливается ошибка ASM_CREATEJOB_FAILED 5113 Job creation of AsyncManager failed
Эмулятор не поддерживает работу с файлами?

Вы уж не сердитесь. Просто много вопросов возникает по ходу "пЪессы". Платформа пока новая, в процессе изучения

Эмулятор действительно не поддерживает работу с файлами.
Используйте виртуальный контроллер:
http://www.owen.ru/forum/showthread.php?t=28167&p=296706&viewfull=1#post296706

RomeoVar
13.07.2021, 21:10
Не можете.
Но можно сделать функцию с сигнатурой типа (pstStructData, szStructData, eStructData) - соответственно, (указатель на экземпляр нужной структуры, размер структуры в байтах, тип структуры).

указатель на экземпляр нужной структуры - POINTER TO BYTE
Под указатель можно подложить что угодно.

А что мне даст входной параметр eStructData если у меня будет только один входной параметр pStructData? Тогда может имеет смысл сделать несколько входных параметров pstStructDataA, pstStructDataB, pstStructDataC и в зависимости от типа eStructData в FB обрабатывать соответствующую входную переменную? Но тогда нужно тщательно контролировать соответствие eStructData типу структуры входного параметра иначе меня будут ждать непредсказуемые "чудеса"

И еще вопрос по ходу: Тут по поводу указателей на экземпляры у меня вопрос - ведь процессор на самом деле 32 разрядный, а это значит что выборка по шине данных происходит, грубо говоря по 4 байта за один цикл чтения по шине данных. Соответственно если структура данных занимает неполных 32 бита, должно происходить выравнивание. Не произойдет ли "искажение" сохраняемых/получаемых данных если использовать POINTER TO BYTE а сами данные будут INT или того хуже FLOAT, или вообще какие-нибудь сложные структуры?

Евгений Кислов
14.07.2021, 04:44
А что мне даст входной параметр eStructData если у меня будет только один входной параметр pStructData?

С помощью "одного входного параметра pStructData" можно передать в блок любые данные любых типов.


Но тогда нужно тщательно контролировать соответствие eStructData типу структуры входного параметра иначе меня будут ждать непредсказуемые "чудеса"]]

Это справедливое высказывание. Программирование - оно вообще во многом именно про "тщательно контролировать".


И еще вопрос по ходу: Тут по поводу указателей на экземпляры у меня вопрос - ведь процессор на самом деле 32 разрядный, а это значит что выборка по шине данных происходит, грубо говоря по 4 байта за один цикл чтения по шине данных. Соответственно если структура данных занимает неполных 32 бита, должно происходить выравнивание. Не произойдет ли "искажение" сохраняемых/получаемых данных если использовать POINTER TO BYTE а сами данные будут INT или того хуже FLOAT, или вообще какие-нибудь сложные структуры?

Выравнивание памяти в структурах есть.
Пользователь должен учитывать его при обработке структур.
См. также:
https://help.codesys.com/webapp/_cds_pragma_attribute_pack_mode;product=codesys;ve rsion=3.5.17.0

RomeoVar
14.07.2021, 08:17
С помощью "одного входного параметра pStructData" можно передать в блок любые данные любых типов.
Спрошу иначе. Какой тип pStructData будет объявлен в FB?

Я сделал так:

FUNCTION_BLOCK SaveDataToFile
VAR_INPUT
sFileName : STRING;
pstDataMC : POINTER TO MACHINE_CONFIG;
pstDataRCP : POINTER TO RECIPIES;
pstDataDP : POINTER TO DRIVE_PARAMS;
szData : UINT;
eNameData : STRUCT_NAME;
END_VAR

А в коде FB я обрабатываю так (кусок логики):

FILE_WORK.WRITE:
CASE eNameData OF
STRUCT_NAME.MACHINE_CONFIG:
fbFileWrite(xExecute:=TRUE, hFile:=hFile, pBuffer:=pstDataMC, szSize:=szData);
STRUCT_NAME.DRIVE_PARAMS:
fbFileWrite(xExecute:=TRUE, hFile:=hFile, pBuffer:=pstDataDP, szSize:=szData);
STRUCT_NAME.RECIPIES:
fbFileWrite(xExecute:=TRUE, hFile:=hFile, pBuffer:=pstDataRCP, szSize:=szData);
END_CASE
IF fbFileWrite.xDone THEN
fbFileWrite(xExecute:=FALSE);
CASE eNameData OF
STRUCT_NAME.MACHINE_CONFIG:
wCRC16_std := MEM.CRC16_standard(pMemoryBlock := pstDataMC, uiLength := szData);
STRUCT_NAME.DRIVE_PARAMS:
wCRC16_std := MEM.CRC16_standard(pMemoryBlock := pstDataDP, uiLength := szData);
STRUCT_NAME.RECIPIES:
wCRC16_std := MEM.CRC16_standard(pMemoryBlock := pstDataRCP, uiLength := szData);
END_CASE
enState := FILE_WORK.WRITE_CRC;
END_IF
IF fbFileWrite.xError THEN
CASE enFileErr OF
; //Обработчик ошибок
END_CASE
END_IF

МОжет можно проще, но я не понял как

Евгений Кислов
14.07.2021, 08:20
Спрошу иначе. Какой тип pStructData будет объявлен в FB?

POINTER TO BYTE, например.
Если для блока содержание структуры не имеет значения (например, нет необходимости ее парсить) - то eNameData вообще не нужен.

RomeoVar
14.07.2021, 08:28
POINTER TO BYTE, например.

А PVOID не лучше? Я просто с ним никак не разберусь. В Си есть тип переменной VOID, который как раз и используется в случаях когда заранее не известен принимаемый тип. Если это так, то PVOID будет лучше чем POINTER TO BYTE

Евгений Кислов
14.07.2021, 09:16
А PVOID не лучше? Я просто с ним никак не разберусь. В Си есть тип переменной VOID, который как раз и используется в случаях когда заранее не известен принимаемый тип. Если это так, то PVOID будет лучше чем POINTER TO BYTE

В CODESYS указатели фактически хранятся как переменные типа DWORD (для 32-битных платформ) или LWORD (для 64-битных платформ).
POINTER TO <TYPE> - это синтаксический сахар над этим DWORD/LWORD, который позволяет компилятору проверять соответствие типов при разыменовании и обеспечивать индексный доступ.
CAA.PVOID - это просто псевдоним (ALIAS) для типа __XWORD. Это платформо-зависимый тип, который на 32-битных платформах превращается в DWORD, а на 64-битных - в LWORD.

Поэтому принципиальной разницы между описанными вами вариантами для описанной вами ситуации я вообще не вижу.

RomeoVar
14.07.2021, 09:47
ТАк правильно объявлять переменную с таким типом правильно как ?

POINTER TO CAA.PVOID

или просто
CAA.PVOID т.к. это уже указатель?

Евгений Кислов
14.07.2021, 09:50
ТАк правильно объявлять переменную с таким типом правильно как ?

POINTER TO CAA.PVOID

или просто
CAA.PVOID т.к. это уже указатель?

Просто CAA.PVOID.

RomeoVar
16.07.2021, 15:10
Не буду заводить новую тему. Спрошу здесь, если нужно завести новую - скажете, заведу.
У меня вопрос по перечислениям. Есть механизм, позволяющий получить следующий элемент перечисления?
Есть код типа

CASE enVAR OF
ENUM.ELEM1: ...

ENUM.ELEM2
END_CASE
В ENUM.ELEM1, ENUM.ELEM2 Вызывается одна и та-же функция, только с другими параметрами. Хочу завернуть это в цикл - так существенно сократится код

capzap
16.07.2021, 15:37
Не буду заводить новую тему. Спрошу здесь, если нужно завести новую - скажете, заведу.
У меня вопрос по перечислениям. Есть механизм, позволяющий получить следующий элемент перечисления?
Есть код типа

CASE enVAR OF
ENUM.ELEM1: ...

ENUM.ELEM2
END_CASE
В ENUM.ELEM1, ENUM.ELEM2 Вызывается одна и та-же функция, только с другими параметрами. Хочу завернуть это в цикл - так существенно сократится код
а зачем сложно то так, зачем перечисления если и просто INT подойдет, хотите чтоб значение имело какой то смысл объявите константы

RomeoVar
16.07.2021, 17:28
Да, согласен, сложно. Башка, видимо, уже закипает от объема информации. Не хотел новую переменную добавлять