LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Profibus DLL implementation doesn't work

Solved!
Go to solution

Hello!

Regarding the same project I had already asked something concerning the actual DLL call, which works fine now. The next step would be, of course, to use the DLL. However, at least one specific call (DPReadSlave) doesn't work. The code is attached, but since the DLL is for a RS232-to-Profibus adapter you cannot run it. The ZIP includes the test example, the Win32 demo and the lib made by the LV DLL importer. 

What happens:

  • The init, open and read calls work in the example. DPReadSlave is supposed to read cyclic process data from the slave, but the structure/array remains unchanged in the input data. The same thing in a compiled EXE from a demo project works.
  • I have tried two, actually three ways: a) manually creating a cluster that is mostly the same as the structure defined in the header file, b) replacing the cluster by a 1456 byte U8 array and c) importing the specific function call of DPReadSlave (or DPOpenSlave) via the LV DLL importer, but it got stuck on those function because of the complex structure. Replacing the structure in the header file by an equally sizes array makes it of course work.
    • The structure in question, stDpData, is supposed to be 1451 bytes when counting in the header file prof_dp.dll. When putting out a sizeof () in the EXE, it returns 1456 as length.

At the moment I'm not sure what the reason is. Is it the structure/array format or is the call itself? There are quite a few options in the DLL cal VI and I think I tried them all. According to the little information in the header file and the demo project, cyclic data reading is done by the DPReadSlave function call directly and should place read data in the ucInputData part of stDpData.

 

https://1drv.ms/u/s!AsxWw7aBKdXkgQ0lfeOC19iNJB4q?e=YLk7bl 

0 Kudos
Message 1 of 15
(1,491 Views)

Addition: the DPOpenSlave function is supposed to return 20 on success, but it does that only once. Next time it's 65556 and it keeps adding up. I'm not sure if this is really caused by the DLL or by LV, because when I close all LV windows, start LV again and run the example the first time, the value will be 20 again.

0 Kudos
Message 2 of 15
(1,474 Views)
Solution
Accepted by topic author MaSta

@MaSta wrote:

The structure in question, stDpData, is supposed to be 1451 bytes when counting in the header file prof_dp.dll. When putting out a sizeof () in the EXE, it returns 1456 as length.

You forgot to account for alignment!

Rolf Kalbermatter
My Blog
Message 3 of 15
(1,453 Views)

You cannot type cast your cluster to a byte array and pass it to the library. Two things happen:

- the data is packed

- the data is converted to big endian format

 

LabVIEW 32 bit also stores bytes back to back, but your other compiler does not, see here: https://knowledge.ni.com/KnowledgeArticleDetails?id=kA00Z0000019YsYSAU&l=en-US.

Message 4 of 15
(1,442 Views)

I managed to get the DPReadSlave working by switching the DLL call in particular VI back to cluster input instead of array input.

 

What I currently find weird is what would be considered as BOOL in terms of Win32. I know, a boolean variable under Win32 has 32 bit, but what value represents TRUE? From the bOperate bit in the stDpData I learned it seems to be 0x00000100. That makes me wonder if the bytes could be swapped, because for TRUE I would expect 0x00000001. However, it seems that any value >0 is considered as TRUE.

0 Kudos
Message 5 of 15
(1,435 Views)

The official Windows documentation says that 0 is FALSE and anything else is TRUE. You can't rely on 1 being used for TRUE!

 

This is consistent with C logic. You don't really have a boolean in C.

 

If you want to test an element for boolean values you have to test like this:

 

 

int booleanVal;
int booleanArray;
#define SOME_BOOL_MASK  0x0100

if (booleanVal)
    printf("TRUE");

if (!booleanVal)
    printf("TRUE");

if (booleanArray & SOME_BOOL_MASK)
    printf("Bit 0x%x is TRUE", SOME_BOOL_MASK);

if (!(booleanArray & SOME_BOOL_MASK))
    printf("Bit 0x%x is FALSE", SOME_BOOL_MASK);

 

 

 

Rolf Kalbermatter
My Blog
Message 6 of 15
(1,425 Views)

@rolfk wrote:

@MaSta wrote:

The structure in question, stDpData, is supposed to be 1451 bytes when counting in the header file prof_dp.dll. When putting out a sizeof () in the EXE, it returns 1456 as length.

You forgot to account for alignment!


I recently read something about packing, but didn't consider it as I expected LV to pass it correctly to the DLL. Found this in a knowledge base article of NI:

In Win-32 environments, LabVIEW stores cluster elements back to back with a packing size of 1 byte, as demonstrated in the How LabVIEW Stores Data in Memory topic in the LabVIEW Help. Meaning, regardless of which members are in the cluster, there are no extra bytes between one element and the next. The default settings for Visual Studio, however, will pack items according to their natural alignment and a default packing size of 8 bytes.

 

OK, so the struct elements are packed in groups of 8 bytes. I would have to expect the Visual Studio compiler to add fill bytes for those elements not fitting into a group of 8 bytes, which would explain why sizeof() returns 1456. Means, in my struct definition I will also have to put some fill bytes? And where? I cannot even know if the compiler would perhaps rearrange the struct elements in memory to fill up groups of 8 bytes.

The struct by definition is 1451 bytes, in the demo memory it's 1456, so 5 fill bytes. Going through the struct, counting the elements' sizes that would fit into groups of 8 bytes and  I end up having way more fill bytes than 5. 

0 Kudos
Message 7 of 15
(1,411 Views)

@MaSta wrote:

 

OK, so the struct elements are packed in groups of 8 bytes. I would have to expect the Visual Studio compiler to add fill bytes for those elements not fitting into a group of 8 bytes, which would explain why sizeof() returns 1456. Means, in my struct definition I will also have to put some fill bytes? And where? I cannot even know if the compiler would perhaps rearrange the struct elements in memory to fill up groups of 8 bytes.


No, the struct elements are packed at a multiple of 8 bytes or the actual elements datasize, whichever is smaller!

 

There is NO right or wrong packing. It is whatever the client (DLL) was compiled with and there is NO way for the caller to know that automatically. You as programmer are responsible to know what packing is needed if any, what default alignment was used to compile the DLL and have to take care about that when calling DLLs.

 

If you are lucky there is an explicit #pragma pack() statement in the according header that you can see, but it can just as well only be specified in the project file used to compile the DLL.

Rolf Kalbermatter
My Blog
Message 8 of 15
(1,406 Views)

A group of 8 bytes or a multiple of 8. For me it's the same. When some elements' combined size is less, there will be fill data. 

What I now did was to extend the Win32 demo by some code that prints the full 1456 bytes of stDpData into the console window and saved is as a binary file. From the structure starting with:

typedef struct {
unsigned char DPV1_Supported; /* (1 byte) set on startup: enable DPV1 support, */
unsigned char Max_Channel_Data_Length; /* (2 bytes)set on startup: max DPV1 channel length (4..244) */
unsigned char Extra_Alarm_SAP; /* (3 bytes)set on startup: Extra DPV1 Alarm SAP */
unsigned int C1_Response_Timeout; /* (5 bytes)set on startup: C1 Response Timeout */
unsigned char NormParameters [7]; /* (12 bytes)set on startup: norm parameter. Ident number is read from slave */
unsigned char UserParamLength; /* (13 bytes)set on startup: user parameter length */
unsigned char UserParameters [248]; /* (261 bytes)set on startup: user parameter */

the NormParameters would start at offset 5, but here start at 8, so there are 3 filled/aligned bytes. 

MaSta_0-1676989578072.png

The rest is filled at the end. So the solution is to stretch the struct by 3 bytes. And indeed, it worked!

 

Thanks for your help. 

0 Kudos
Message 9 of 15
(1,386 Views)

Nope!

 

 

typedef struct {                       offset     size
unsigned char DPV1_Supported;              0        1
unsigned char Max_Channel_Data_Length;     1        1
unsigned char Extra_Alarm_SAP;             2        1
//unsigned char filler1;                   3        1
unsigned int C1_Response_Timeout;          4        4
unsigned char NormParameters [7];          8        7
unsigned char UserParamLength;            15        1
unsigned char UserParameters [248];       16      248
} Struct;                         total size      264

 

 

C1_Response_Timeout is an int and as such only uses 4 byte (on every current platform with the exception of some 8 bit embedded CPUs). Because of that it is aligned on a 4 byte boundary even if the default alignment is set to 8 byte!

Rolf Kalbermatter
My Blog
0 Kudos
Message 10 of 15
(1,382 Views)