I need to divide a STRUCT into 8-Byte portions (ULINT) in order to send them via CAN.
Any suggestions and experience how this could be done? The size of the Structures is known (e.g. 256 Bytes).
Many thanks and regards,
Fabian
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
WHILE uiOffset < uiTotalSize DO
// check to see if divisible by 8 (e.g. STRUCT is 249 bytes instead of 256).
// could use MOD, but costly
IF (uiTotalSize - uiOffset < uiDataBlock) THEN
uiDataBlock := uiTotalSize - uiOffset;
END_IF
uliData := 0; // reset to be sure
// copy data from struct to ULINT
MemCpy(pbyDest:=ADR(uliData), pbySrc:=pbStruct+uiOffset, dwSize:=uiDataBlock);
// send data via CAN here
// if success increment by uiDataBlock, else retry logic
uiOffset := uiOffset + uiDataBlock;
END_WHILE
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Many thanks for your answer, it works like it should!
I was struggling yesterday with memcpy as it was not clear to me that only 1 byte at a time can be copied.
Now I only have the problem, that my STRUCT contains BOOLEANS and they unfortunately occupy 1 Byte instead of 1 Bit only which then extends the length of the structure unintended. (The BOOL should only occupy 1 bit on the CAN as the receiver side is given)
I already noticed that this is a known topic and I will do some more research on that - unless you have a solution in your pocket? :-)
A typical structure for 32-Bytes could look like this:
Hello,
I need to divide a STRUCT into 8-Byte portions (ULINT) in order to send them via CAN.
Any suggestions and experience how this could be done? The size of the Structures is known (e.g. 256 Bytes).
Many thanks and regards,
Fabian
You could:
1. use SIZEOF to get the total size of the STRUCT in bytes.
2. use memcpy to copy chunks of 8 bytes at a time: https://help.codesys.com/webapp/ZidVRTnfzfI0LAYUwLYCsY_W-O4%2FMemCpy;product=MemoryUtils;version=3.5.17.0
3. Increment index offset using while/for loop until you're at the end.
don't have codesys open, but something like the below should work.
// VAR
uliData : ULINT;
uiOffset : UINT := 0;
pbStruct : POINTER TO BYTE;
uiTotalSize : UINT := 0;
uiDataBlock : UINT := 8;
pbStruct := ADR(myStruct);
uiTotalSize := SIZEOF(myStruct);
WHILE uiOffset < uiTotalSize DO
// check to see if divisible by 8 (e.g. STRUCT is 249 bytes instead of 256).
// could use MOD, but costly
IF (uiTotalSize - uiOffset < uiDataBlock) THEN
uiDataBlock := uiTotalSize - uiOffset;
END_IF
uliData := 0; // reset to be sure
// copy data from struct to ULINT
MemCpy(pbyDest:=ADR(uliData), pbySrc:=pbStruct+uiOffset, dwSize:=uiDataBlock);
// send data via CAN here
// if success increment by uiDataBlock, else retry logic
uiOffset := uiOffset + uiDataBlock;
END_WHILE
Hi nothingrandom,
Many thanks for your answer, it works like it should!
I was struggling yesterday with memcpy as it was not clear to me that only 1 byte at a time can be copied.
Now I only have the problem, that my STRUCT contains BOOLEANS and they unfortunately occupy 1 Byte instead of 1 Bit only which then extends the length of the structure unintended. (The BOOL should only occupy 1 bit on the CAN as the receiver side is given)
I already noticed that this is a known topic and I will do some more research on that - unless you have a solution in your pocket? :-)
A typical structure for 32-Bytes could look like this:
Many thanks and best regards,
Fabian
Hi,
I have solved the problem by packing the bits into bytes (and changing the STRUCT accordingly).
Thanks and regards,
Fab
You could also just use bits of a UDINT since it also has 32 bits. For example:
udiTest : UDINT;
udiTest.0 = TRUE; // same as BOOL1
udiTest.1 = False; // same as BOOL2
Thanks, in the end I used "BIT" type. :-)
tip, try a UNION next time...
https://help.codesys.com/webapp/_cds_datatype_union;product=codesys;version=3.5.12.0
Last edit: hermsen 2022-07-15