FORUM CTRLX AUTOMATION
ctrlX World Partner Apps for ctrlX AUTOMATION
09-27-2021 05:09 AM
Hello,
How to read flatbuffer types and parse flatbuffer types to simple type by CXA_DataLayer lib? Is there some example for this topic?
Solved! Go to Solution.
09-27-2021 11:05 AM - edited 09-27-2021 11:12 AM
See an example I made for reading a safe area:
Declaration:
PROGRAM POU
VAR
bRead: BOOL;
fbDL_ReadNodeValue: DL_ReadNodeValue;
DataRead: CXA_Datalayer.DL_NodeValue;
strNodePath : STRING;
bExecute: BOOL;
bDone: BOOL;
bActive: BOOL;
bError: BOOL;
ErrorID: CXA_Datalayer.ERROR_CODE;
ErrorIdent: CXA_Datalayer.ERROR_STRUCT;
strName : STRING := 'Zone_1';
fbAreas_Read: CXA_MotionCore_fbs.motion_core_fbtypes_SysCfgSafeArea;
Read_CoordSys: STRING;
Read_Name: STRING;
Read_Type: CXA_MotionCore_fbs.motion_core_fbtypes_SafeAreaType;
Read_Boxes_length: UDINT;
Read_Boxes: POINTER TO CXA_MotionCore_fbs.motion_core_fbtypes_SysCfgSafeAreaBox;
Read_Boxes_Int: CXA_MotionCore_fbs.motion_core_fbtypes_SysCfgSafeAreaBox;
arRead_Active: ARRAY [0..2] OF BOOL;
arRead_Max:ARRAY [0..2] OF LREAL;
arRead_Min: ARRAY [0..2] OF LREAL;
arRead_Unit: ARRAY [0..2] OF STRING;
i: INT;
END_VAR
Implementation:
IF bRead THEN
bRead := FALSE;
strNodePath := CONCAT('motion/cfg/safe-areas/',strName);
bExecute := TRUE;
END_IF
IF fbDL_ReadNodeValue.Done THEN
fbAreas_Read.getRootAsSysCfgSafeArea(data:= DataRead.GetData(), size:= DataRead.GetSize());
Read_CoordSys := fbAreas_Read.getCoordSystem();
Read_Name := fbAreas_Read.getName();
Read_Type := fbAreas_Read.getType();
Read_Boxes_length := fbAreas_Read.getBoxLength();
FOR i := 0 TO TO_INT(Read_Boxes_length)-1 BY 1 DO
Read_Boxes := fbAreas_Read.getBox(i);
Read_Boxes_Int := Read_Boxes^;
arRead_Active[i] := Read_Boxes_Int.getActive();
arRead_Max[i] := Read_Boxes_Int.getMax();
arRead_Min[i] := Read_Boxes_Int.getMin();
arRead_Unit[i] := Read_Boxes_Int.getUnit();
END_FOR
bExecute := FALSE;
END_IF
fbDL_ReadNodeValue(
Execute:= bExecute,
Done=> bDone,
Active=> bActive,
Error=> bError,
ErrorID=> ErrorID,
ErrorIdent=> ErrorIdent,
ClientId:= ,
NodeName:= strNodePath,
NodeValue:= DataRead);
09-28-2021 05:58 AM
Hello,
Thanks a lot for your sample. It's pretty helpful.
I'm reading fbs script_manager_fbtypes_DiagInfo which inculdes string type and array of string type, there are sitll some problems for me:
1. When trying to parse array of string, I can get a valid value of pointer to string by getLasetErrTrace method, but when convert it to string type, I always get invalid result.
2. Besides, I can always get a value(not zero) by method strPtr := fbsDiag_Read.getLastErrTrace(idx), even though idx is bigger than count.
count := fbsDiag_Read.getLastErrTraceLength();
FOR idx := 0 TO count - 1 DO
strPtr := fbsDiag_Read.getLastErrTrace(idx);
IF strPtr <>0 THEN
Stu.StrCpyA(pBuffer:=ADR(testStr), iBufferSize := SIZEOF(testStr), pStr := strPtr);
END_IF
END_FOR
3. When trying to read a string longer than 80 length, it's limited to 80(default string length in codesys). For some case, it's not enough to get a string with wrong length.
ErrorStr := fbsDiag_Read.getLastErrText();
10-01-2021 11:57 AM
I do not get all of your points. Please see my version that works as I expected:
Declaration:
PROGRAM script_manager_fbtypes_DiagInfo
VAR
strMyInstancename : STRING := 'MyInstance';
bRead: BOOL;
bExecute: BOOL;
strNodePath: STRING(255);
fbDL_ReadNodeValue: DL_ReadNodeValue;
bDone: BOOL;
bActive: BOOL;
bError: BOOL;
ErrorID: CXA_Datalayer.ERROR_CODE;
ErrorIdent: CXA_Datalayer.ERROR_STRUCT;
DataRead: CXA_Datalayer.DL_NodeValue;
fbDiagInfo: cxa_automationcore_fbs.script_manager_fbtypes_DiagInfo;
udiLastMainDiag: UDINT;
udiLastDetailDiag: UDINT;
strLastErrText: STRING(255);
udiLastErrTraceLength: UDINT;
i: INT;
arstrLastErrTrace: ARRAY [0..99] OF STRING;
pLastErrTrace: POINTER TO STRING;
END_VAR
Implementation:
IF bRead THEN
bRead := FALSE;
strNodePath := CONCAT('script/instances/',strMyInstancename);
strNodePath := CONCAT(strNodePath,'/diag');
bExecute := TRUE;
END_IF
IF fbDL_ReadNodeValue.Done THEN
fbDiagInfo.getRootAsDiagInfo(data:= DataRead.GetData(), size:= DataRead.GetSize());
udiLastMainDiag := fbDiagInfo.getLastMainDiag();
udiLastDetailDiag := fbDiagInfo.getLastDetailDiag();
strLastErrText := fbDiagInfo.getLastErrText();
udiLastErrTraceLength := fbDiagInfo.getLastErrTraceLength();
FOR i := 0 TO TO_INT(udiLastErrTraceLength)-1 BY 1 DO
pLastErrTrace := fbDiagInfo.getLastErrTrace(i);
arstrLastErrTrace[i] := pLastErrTrace^;
END_FOR
bExecute := FALSE;
END_IF
fbDL_ReadNodeValue(
Execute:= bExecute,
Done=> bDone,
Active=> bActive,
Error=> bError,
ErrorID=> ErrorID,
ErrorIdent=> ErrorIdent,
ClientId:= ,
NodeName:= strNodePath,
NodeValue:= DataRead);
Picture:
08-09-2022 05:59 AM
hello,
about how to read array of string type in the datalayer, I follow your example to read the data as below.
I am planed to read the offset-xyz value and offset-xyz-units.it is works to read array of LREAL type, but the array of string is always empty, although the length is corrent.
see my program code:
Declaration:
FUNCTION_BLOCK ReadSets
VAR_INPUT
strName : STRING;
END_VAR
VAR_OUTPUT
END_VAR
VAR
bRead : BOOL;
fbDL_ReadNodeValue: DL_ReadNodeValue;
DataRead: CXA_Datalayer.DL_NodeValue;
strNodePath : STRING;
fbSysCfgPcsSet_Read: motion_core_fbtypes_SysCfgPcsSet;
OffsetXYZ_length : UDINT;
Orientation_Length : UDINT;
OffsetAux_Length : UDINT;
OffsetXYZUnits_Length : UDINT;
pOffsetXYZ : POINTER TO LREAL;
pOrientation : POINTER TO LREAL;
pOffsetAux : POINTER TO LREAL;
pOffsetXYZUnits : POINTER TO STRING;
arOffsetXYZ: ARRAY [0..2] OF LREAL;
arOrientation: ARRAY [0..2] OF LREAL;
arOffsetAux: ARRAY [0..9] OF LREAL;
arOffsetXYZUnits: ARRAY [0..2] OF STRING;
i: UDINT;
END_VAR
Implementation:
IF fbDL_ReadNodeValue.Done THEN
fbSysCfgPcsSet_Read.getRootAsSysCfgPcsSet(data:= DataRead.GetData(), size:= DataRead.GetSize());
OffsetXYZ_length := fbSysCfgPcsSet_Read.getOffsetXYZLength();
Orientation_Length := fbSysCfgPcsSet_Read.getOrientationLength();
OffsetAux_Length := fbSysCfgPcsSet_Read.getOffsetAuxLength();
OffsetXYZUnits_Length := fbSysCfgPcsSet_Read.getOffsetXYZUnitsLength();
//OffsetXYZ
FOR i := 0 TO TO_INT(OffsetXYZ_length)-1 BY 1 DO
pOffsetXYZ := fbSysCfgPcsSet_Read.getOffsetXYZ(i);
arOffsetXYZ[i] := pOffsetXYZ^;
END_FOR
//Offset Orientation
FOR i := 0 TO TO_INT(Orientation_Length)-1 BY 1 DO
pOrientation := fbSysCfgPcsSet_Read.getOrientation(i);
arOrientation[i] := pOrientation^;
END_FOR
//OffsetAux
FOR i := 0 TO TO_INT(OffsetAux_Length)-1 BY 1 DO
pOffsetAux := fbSysCfgPcsSet_Read.getOffsetAux(i);
arOffsetAux[i] := pOffsetAux^;
END_FOR
//OffsetXYZUnits example faild
FOR i := 0 TO OffsetXYZUnits_Length-1 BY 1 DO
pOffsetXYZUnits := fbSysCfgPcsSet_Read.getOffsetXYZUnits(i);
arOffsetXYZUnits[i] := pOffsetXYZUnits^;
END_FOR
bRead := FALSE;
END_IF
//motion/cfg/coord-systems/pcs/sets
strNodePath := CONCAT('motion/cfg/coord-systems/pcs/sets/',strName);
fbDL_ReadNodeValue(
Execute:= bRead,
NodeName:= strNodePath,
NodeValue:= DataRead);
08-09-2022 08:25 AM - edited 08-09-2022 08:26 AM
@leo1 your example is working fine at my side with a small change. In line 24 in my code I also added the unit conversion and declared "i" as integer: