05-26-2014 03:12 PM
Hi!
I have big issues establishing communication over TCP between client app written in CVI and server written in LabView.
First, I created client app in LabView and communication worked fine. In attached picture ‘from_labview_client.jpg’ I pictured server behavior when app was sending two portions of information: first - number of bytes to read in next TCPRead, second – actual information containing measure parameters (three doubles: 2.00, 2.00, 2.00 in cluster). I also attached LabView client block diagram (client_labview.jpg) so you could see how it works.
Then I wanted to achieve the same results using client app written in CVI. As you can see (from_cvi_client.jpg), in the second ClientTCPWrite I struggle to send data in the correct form - I tried sending cluster, but probably I'm doing it somehow wrong.
Could you please help me and point where I make mistake and how to correct it? How to get rid of null values in the beginning of second data out? How to properly cast doubles/cluster to ASCII?
Here is my callback function to send data from client to server:
static unsigned int g_hconversation; static double n_steps; static double max; static double min; int CVICALLBACK start (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { char paramy[4]; switch (event) { case EVENT_COMMIT: GetCtrlVal (panelHandle, PANEL_NUMERIC, &n_steps); //getting values from numeric to variables GetCtrlVal (panelHandle, PANEL_NUMERIC_2, &min); GetCtrlVal (panelHandle, PANEL_NUMERIC_3, &max); typedef struct params params; //struct definiton struct params{ double min; double max; double n_steps; }; struct params struktura; // struct initialization struktura.n_steps = n_steps; struktura.max = max; struktura.min = min; SetWaitCursor (1); int err = ConnectToTCPServer (&g_hconversation, 6341, "", ClientTCPCB, 0, 5000); // establish connection if(err<0) { MessagePopup("TCP Client", "Connection to server failed !"); break; } else { printf("CONNECTED\n"); paramy[0] = 0; paramy[1] = 0; paramy[2] = 0; paramy[3] = sizeof(struktura); err = ClientTCPWrite (g_hconversation,¶my ,sizeof(paramy), -1); err = ClientTCPWrite (g_hconversation, &struktura,sizeof(struktura), -1); } break; } return 0; }
Thanks in advance!
05-26-2014 05:41 PM
A start of a solution but not all ... I see something that I (as amateur) do not recognize as valid.
With respect to you question ... you send the structure as a binary block.
The TCP function gets a pointer to that block. If you get a warning, you can cast is e.g. (unsigned char *)&struktura
One line before, you send the char array. That is what I do not understand.
You have a 4-byte character array paramy. So paramy itself is a pointer to the start of this array. Or ¶my[0] is the same pointer. But ¶my is the address where the pointer is stored. Still you get receive the value 24 at your server. So it seems ok ...
Unknown for me is labview ... what is the byte-order that labview expects.
And is this the same for client and server
<http://en.wikipedia.org/wiki/Endianness>
One answer for the next problem and before the professionals take over ... be careful when you extend the structure.
Labwindows will have a default for packing data in a structure that probably depends on operating system.
<http://digital.ni.com/public.nsf/allkb/F7E5C9169D09E98586256AF300717B33>
I set at the start before defining the structure: #pragma pack(2)
Next: typedef the structure where all character arrays have even length or single bytes are followed with dummy byte
I end after the structure definition with: #pragma pack()
Succes, Jos
05-27-2014 01:10 AM
P.S.
When reading back my reply, I see (besides all the typing errors) that the second link is lost:
Search for: labview packing
Find article with title: Clusters in LabVIEW Do Not Line Up With Structures in Visual C++
05-28-2014 12:21 AM
First of all,
I would make the struct definition as below and put it outside the callback.
typedef struct _params { double min; double max; double n_steps; } params;
Second,
ClientTCPWrite does not guarantee that all bytes are written in a single call.
You have to call it in a loop until all bytes are sent. See the function help. There is a sample code there.
Third,
JGS is right about byte orders and struct packing.
To make sure your struct's size is exactly same as what you expect, type #pragma pack(1) at the top of your file.
Look up "struct packing" to learn more about the subject.
If you are sending binary structures by using their pointers, client and server applications must agree on the orders of bytes.
This is called "Endianness" and it depends on your hardware (CPU). Make sure client and server has the same endianness.
x86 family of CPU's are all little-endian.
Hope this helps,
05-28-2014 08:08 AM
Note also that whilst Intel x86 & x64 architectures, and CVI on PC, are all little-endian LabVIEW is big-endian - so passing binary data to LabVIEW from almost anything else requires byte reversal at some stage.
05-28-2014 11:49 AM - edited 05-28-2014 11:51 AM
Thanks for all your replies!
As programming in CVI and LabView is new to me, all your suggestions were really helpful and guided me towards solution 🙂
In the end, I decided to modify my LabView server and added 'Reverse string' blocks and reversed order of values in paramy array.
Thanks to this, server correctly reads both data in paramy array and data sent in struct.