GOOGLE ADS

domingo, 24 de abril de 2022

¿Puntero TwinCAT a puntero de tipo indefinido?

Estoy tratando de construir una función que sume una matriz de una sola dimensión de cualquier tipo en TwinCAT.

Soy relativamente inexperto con punteros, por lo que la respuesta puede ser obvia, pero no pude encontrar ninguna solución. Leí todo esto y me ayudó un poco.

T_ARG
Convertir matrices de bytes
Las maravillas de ANY

Mi código conceptual funciona para una matriz INT, pero me di cuenta de que tendría que escribir un bucle FOR para cada tipo de datos para que funcione y eso parece incorrecto. También quería evitar tener un CASO en un bucle FOR, ya que parecía ineficiente.

¿Es posible tener un puntero (de tipo no establecido) a un puntero (de un tipo específico)? Parece posible en C, pero no estoy seguro acerca de IEC-61131.

FUNCTION fn_SumArray: DINT
VAR_INPUT
inArr: ANY;
inElem: ANY;

END_VAR
VAR
i: DINT:= 0;
stepsize: DINT:=1;
pLREAL: POINTER TO LREAL; //64 bit
pREAL: POINTER TO REAL; //32 bit
pBYTE: POINTER TO BYTE; //8 bit
pWORD: POINTER TO WORD; //16 bit
pDWORD: POINTER TO DWORD; //32 bit
pLWORD: POINTER TO LWORD; //64 bit
pSINT: POINTER TO SINT; //8 bit
pUSINT: POINTER TO USINT; //8 bit
pINT: POINTER TO INT; //16 bit
pUINT: POINTER TO UINT; //16 bit
pDINT: POINTER TO DINT; //32 bit
pUDINT: POINTER TO UDINT; //32 bit
pLINT: POINTER TO LINT; //64 bit
pULINT: POINTER TO ULINT; //64 bit
END_VAR
--------------------------------------------------
CASE inElem.TypeClass OF
__SYSTEM.TYPE_CLASS.TYPE_LREAL:
stepsize:= 8;
//set generic pointer here
__SYSTEM.TYPE_CLASS.TYPE_INT:
stepsize:= 2;
//set generic pointer here
ELSE
fn_SumArray:=0;
END_CASE;
FOR i:= 0 TO inArr.diSize-1 BY stepsize DO
genericPointer:= ADR(inarr.pValue[i]);
fn_SumArray:= fn_SumArray +genericPointer^;
END_FOR;



Solución del problema

Por lo que sé, deberá repetir el código para todos los tipos que desee cubrir. CODESYS no tiene una verdadera programación genérica, por lo que es lo que es:

METHOD fn_SumArray: BOOL // if TRUE, then error
VAR_INPUT
arr_first: ANY_NUM;
arr_size: DINT;
sum_out: ANY_NUM;
END_VAR
VAR
i: DINT;
ptr_arr: NUMBER_POINTER; // just a UNION with all number type pointers
ptr_sum: NUMBER_POINTER;
END_VAR
// ---------------------------
IF (arr_first.TypeClass <> sum_out.TypeClass) THEN
fn_SumArray:= TRUE;
FOR i:= 0 TO sum_out.diSize - 1 DO
sum_out.pValue[i]:= 0;
END_FOR
RETURN;
END_IF
CASE arr_first.TypeClass OF
__SYSTEM.TYPE_CLASS.TYPE_LREAL:
ptr_arr._LREAL:= arr_first.pValue;
ptr_sum._LREAL:= sum_out.pValue;
ptr_sum._LREAL^:= 0;
FOR i:= 0 TO arr_size - 1 DO
ptr_sum._LREAL^:= ptr_sum._LREAL^ + ptr_arr._LREAL[i];
END_FOR
// Repeat the above for all...
ELSE
fn_SumArray:= TRUE;
FOR i:= 0 TO sum_out.diSize - 1 DO
sum_out.pValue[i]:= 0;
END_FOR
END_CASE;

PROGRAM PLC_PRG
VAR CONSTANT
SIZE: DINT:= 50;
END_VAR
VAR
i: DINT;
arr_int: ARRAY [0..(SIZE - 1)] OF INT;
sum_int: INT;
arr_dint: ARRAY [0..(SIZE - 1)] OF DINT;
sum_dint: DINT;
arr_real: ARRAY [0..(SIZE - 1)] OF REAL;
sum_real: REAL;
first_run: BOOL:= TRUE;
sum_test: REAL;
test_failed: BOOL;
END_VAR
// ---------------------------
IF (first_run) THEN
first_run:= FALSE;
FOR i:= 0 TO SIZE - 1 DO
arr_int[i]:= DINT_TO_INT(i);
arr_dint[i]:= i * 10;
arr_real[i]:= DINT_TO_REAL(i) / 10;
END_FOR
END_IF
fn_SumArray(arr_first:= arr_int[0], arr_size:= SIZE, sum_out:= sum_int);
sum_test:= 0;
FOR i:= 0 TO SIZE - 1 DO
sum_test:= sum_test + arr_int[i];
END_FOR
IF (sum_int <> REAL_TO_INT(sum_test)) THEN
test_failed:= TRUE;
END_IF
fn_SumArray(arr_first:= arr_dint[0], arr_size:= SIZE, sum_out:= sum_dint);
sum_test:= 0;
FOR i:= 0 TO SIZE - 1 DO
sum_test:= sum_test + DINT_TO_REAL(arr_dint[i]);
END_FOR
IF (sum_dint <> REAL_TO_DINT(sum_test)) THEN
test_failed:= TRUE;
END_IF
fn_SumArray(arr_first:= arr_real[0], arr_size:= SIZE, sum_out:= sum_real);
sum_test:= 0;
FOR i:= 0 TO SIZE - 1 DO
sum_test:= sum_test + arr_real[i];
END_FOR
IF (sum_real <> sum_test) THEN
test_failed:= TRUE;
END_IF

El resultado del programa anterior:

captura de pantalla de codesys

Si escribir el mismo código para cada tipo es demasiado tedioso, siempre puede usar un script para automatizar esto:

code_template = \
"""CASE arr_first.TypeClass OF
{0}
ELSE
\tfn_SumArray:= TRUE;
\tFOR i:= 0 TO sum_out.diSize - 1 DO
\t\tsum_out.pValue[i]:= 0;
\tEND_FOR
END_CASE;
"""
case_template = \
"""\t__SYSTEM.TYPE_CLASS.TYPE{0}:
\t\tptr_arr.{0}:= arr_first.pValue;
\t\tptr_sum.{0}:= sum_out.pValue;
\t\tptr_sum.{0}^:= 0;
\t\tFOR i:= 0 TO arr_size - 1 DO
\t\t\tptr_sum.{0}^:= ptr_sum.{0}^ + ptr_arr.{0}[i];
\t\tEND_FOR
"""
types = ['_REAL', '_LREAL', '_USINT', '_UINT', '_UDINT', '_ULINT', '_SINT', '_INT', '_DINT', '_LINT']
cases = [case_template.format(t) for t in types]
code = code_template.format(''.join(cases))
print(code)

Simplemente ejecute la secuencia de comandos anterior con python y obtendrá el código de caso para los tipos enumerados en la secuencia de comandos.

No hay comentarios:

Publicar un comentario

Regla de Firestore para acceder a la generación de subcolección Permisos faltantes o insuficientes

Tengo problemas con las reglas de Firestore para permitir el acceso a algunos recursos en una subcolección. Tengo algunos requests document...