LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Reading C Structure over TCP in LabVIEW

Hi,

I want to read the "parseSrvCmd" structure sent by a C program over TCP in LabVIEW. The "parseSrvCmd" is composed of two structures (_srv_BasicFlds and _srv_DataPkt)- c code is provided towards end of this post.

After searching through this forum, came to know that, the output string from TCP read vi function needs to be correctly typecast to match the C structure in terms of data types and pragma packing.

Can any one guide me, with the correct data types/ cluster elements to be used for typecasting- especially for
"char prmname[MAXDATA][DATALEN]"? What will be effect of pragma packing on the LabVIEW code, while trying to typecast/ separate the individual fields of cluster?


--------------------C code for Strucure ------------
#define  MAXDATA 128
#define  DATALEN 64
#define  MSGLEN 128

#pragma pack(push,1)

typedef struct _srv_BasicFlds{
  int seq;
  float version;
  short priority ;
  short timeout ;
  char subsysid[DATALEN];    
  char cmdname[DATALEN];
  char timestamp[DATALEN];
  char id[8];

} _srv_BasicFlds;

/* data information */
typedef struct _srv_DataPkt{
     short numpkt;
     char prmname[MAXDATA][DATALEN];  
     char prmvalue[MAXDATA][DATALEN];
} _srv_DataPkt;


typedef struct parseSrvCmd
{
  _srv_BasicFlds cmdelem;
  _srv_DataPkt data;

} parseSrvCmd ;

#pragma pack(pop)

0 Kudos
Message 1 of 15
(4,868 Views)

First the pragma pack(1) will cause the C compiler to pack everything maximally. This is also the LabVIEW default.

 

Second, the only valid datatype for "char elm[DATALEN]"  that allows to directly typecast the bytestream into a LabVIEW cluster is another cluster with DATALEN (un)signed 8 bit integers. These are not normal C strings anyways but fixed size arrays, which get directly inlined in the C structure (which is the only way to specify a bytestream protocol in C type definitions without adding a special flatten and unflatten function in between which collects the various sparse data elements from pointers and packs them into a stream and vice versa.

After that you have to go through each of those byte arrays and convert them into a string and create a native LabVIEW data cluster which uses normal strings (or arrays for binary data). The length of the byte array can be defined by a different element in your structure or for strings usually is indicated by a NULL character.

 

Personally I often directly go through the bytestream and parse the different elements from it into the final LabVIEW data cluster which contains the correct datatypes such as strings, arrays, sub clusters and scalar elements.

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
0 Kudos
Message 2 of 15
(4,845 Views)
I have also worked on applications where the C-side developer simply converted the struct to a JSON string (he said that there was a built-in library function to do that) and then sent that string via TCP. On the LabVIEW side I unflattend the JSON into a cluster.

Mike...

Certified Professional Instructor
Certified LabVIEW Architect
LabVIEW Champion

"... after all, He's not a tame lion..."

For help with grief and grieving.
0 Kudos
Message 3 of 15
(4,820 Views)
Well, it seems the cluster that I would need to provide as an input to the Type cast function would be something like represented below. I hope I am heading towards correct path. But, I am also concerned about the performance of LabVIEW for procesing such a complex data type at every one second. Else, I might be making some mistakes in forming this cluster. Pl. guide. Element 1: int seq >> U32 Element 2: float version >> SGL Element 3: short priority >> U16 Element 4: short timeout >> U16 Element 5: char subsysid[DATALEN] >> U8 Array [64] (DATALEN is 64) Element 6: char cmdname[DATALEN] >> U8 Array [64]   Element 7: char timestamp[DATALEN] >> U8 Array [64] Element 8: char id [8] >> U8 Array [8] Element 9: short numpkt >> U16 Element 10 to Element 138: char prmname[MAXDATA][DATALEN] >>>> U8 Array [64] (representing 128 rows of this 2D array sent in a structure and DATALEN = 64) Element 139 to Element 266: char prmvalue[MAXDATA][DATALEN] >>>> U8 Array [64] (representing 128 rows of this 2D array sent in a structure and DATALEN = 64) I do not have a choice for asking the developer to change the code. Actually, I am trying to simulate a response of a legacy hardware device.
0 Kudos
Message 4 of 15
(4,801 Views)

The problem you have is that you can't define a fixed length Array in a cluster type in LabVIEW.

The fixed length array have to be a cluster in LabVIEW.

 

LabVIEW should easily be able to convert the byte to a type every second. I think even if you manualy to through the bytes.

0 Kudos
Message 5 of 15
(4,789 Views)

Thanks, I realised that. So the corrected cluster becomes as described below. Would like to know about the correctness of datatypes and lenth of the cluster elements as well.


 

 

Element 1: int seq >> U32

Element 2: float version >> SGL

Element 3: short priority >> U16

Element 4: short timeout >> U16

 

Element 5: char subsysid[DATALEN] >> U8 cluster [64 elements] (DATALEN is 64)

Element 6: char cmdname[DATALEN] >> U8 cluster [64 elements] 

Element 7: char timestamp[DATALEN] >> U8 cluster [64 elements]

 

Element 8: char id [8] >> U8 cluster [64 elements]

Element 9: short numpkt >> U16

 

Element 10 to Element 138: char prmname[MAXDATA][DATALEN] >>>> U8 cluster [64 elements] (representing 128 rows of this 2D array sent in a structure and DATALEN = 64)

 

Element 139 to Element 266: char prmvalue[MAXDATA][DATALEN] >>>> U8 cluster [64 elements] (representing 128 rows of this 2D array sent in a structure and DATALEN = 64)

0 Kudos
Message 6 of 15
(4,769 Views)

@ITA wrote:

Thanks, I realised that. So the corrected cluster becomes as described below. Would like to know about the correctness of datatypes and lenth of the cluster elements as well.


 

 

Element 1: int seq >> I32

Element 2: float version >> SGL

Element 3: short priority >> I16

Element 4: short timeout >> I16

 

Element 5: char subsysid[DATALEN] >> U8 cluster [64 elements] (DATALEN is 64)

Element 6: char cmdname[DATALEN] >> U8 cluster [64 elements] 

Element 7: char timestamp[DATALEN] >> U8 cluster [64 elements]

 

Element 8: char id [8] >> U8 cluster [8 elements]

Element 9: short numpkt >> I16

 

Element 10 to Element 8202: char prmname[MAXDATA][DATALEN] >>>> U8 cluster [64*128 = 8192 elements] (representing 128 rows of this 2D array sent in a structure and DATALEN = 64)

 

Element 8202 to Element 16484: char prmvalue[MAXDATA][DATALEN] >>>> U8 cluster [64*128 = 8192 elements] (representing 128 rows of this 2D array sent in a structure and DATALEN = 64)


Quite a few errors!! And all except the U(nsigned) to I(nteger) mismatches definitely fatal for reading the right data.

Especially for the last 2 elements I would not include them in the typecast but process them seperately.

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
0 Kudos
Message 7 of 15
(4,751 Views)
Thank you for correcting me. Could you please elaborate the following line- an example code may be of great Especially for the last 2 elements I would not include them in the typecast but process them separately. With my knowledge of subject and familiarity with LabVIEW, I had planned to do it as per the attached vi. But observed that, LabVIEW crashes frequently- though haven't run this program- not confident, if this will run even. May be because the complex nature of clusters placed on front panel. Can you please suggest modifications to this program/ share your sample code. Thank You!
0 Kudos
Message 8 of 15
(4,729 Views)

Your super mega pronto saurus cluster is going to give you very much trouble. LabVIEW maintains a complete recursive type description of all its datatypes and such a cluster causes a typedescriptor of many kB length that LabVIEW repeatedly has to parse every time you do some edit operation on the diagram. Not a good idea at all and anyhow not really helpful.

 

I would do it more along these lines as attached. There are still many open ends so far that I can not fill in for you. The strings that get returned may not always be 64 or 8 characters long but shorter, having a NULL character as termination indication. So you might need to create a subVI that goes through each character byte by byte until it sees a NULL byte.

 

I also assumed that numpkt is the number of effectively available data packets in the stream rather than always 128. That may or may not be correct, I don't know but from other experiences it seems like a good guess.

 

Data_Packet_TypeCast.png

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
0 Kudos
Message 9 of 15
(4,716 Views)

Thank you for your help- I am able to read the structures.

 

But facing a different problem now. How do I determine the end of structure/ start of structure, while I am trying to read it over TCP? There are no special provisions made in the packet/structure to determine the start / end of structure. Any suggestions on how to tackle this issue?

0 Kudos
Message 10 of 15
(4,684 Views)