I have an MCU unit that is connected to the local network. This device is sending it's status data over a TCP socket 100 times per second. Over the same socket I can also issue commands and data.
I'm trying to write a simple TCP client that could connect to the device, grab the data and if requested send commands. Currently I can send commands without problems (the commands are sent as strings and this works). My problem is reception of the data FROM device.
I know from the device manual that the data should be a 32 bit integer first, then an array of approximately 30 doubles)
I am establishing a new thread that I want to contineously intercept the data and process it:
void *com::setListenerSocket(void* threadSocketData) {
struct socketData *sockData;
sockData = (socketData*)threadSocketData;
com::tcp_client cListener;
struct timeval timeout;
timeout.tv_sec=0;
timeout.tv_usec=12500;
// setsockopt(cListener, IPPROTO_TCP, SO_RCVTIMEO, (char *)timeout, sizeof(timeout)); //no effect
cListener.connect(sockData->host , sockData->port);
cout << "listener thread started" << endl;
cout << "host=" << sockData->host << " at port=" << sockData->port << endl;
cListener.send_data("Listener Reporting\n");
while(listenerRun){
listenerHB++;
cout << endl <<"***************************** BGN *************************************************************"<< endl;
char *received = new char[PACKETSIZE];
cListener.receive(PACKETSIZE, received);
unsigned int test;
test = (uint32_t) received;
cout << "received=" << test << endl;
for(int i = 0; i< PACKETSIZE ; ++i)
cout << received[i] << ", ";
cout << endl <<"***************************** END *********************************************"<< endl;
robotPacket data;
//parseData(received, &data);
//usleep(1 MS);
}
cout << "listener signing out" << endl;;
pthread_exit(NULL);
}
and the listener method is:
void com::tcp_client::receive(int size, char* buffer) {
unsigned int bytecnt = 0, archive = 1;
while(bytecnt < (unsigned int)size) {
// bytecnt += recv(sock , &buffer[bytecnt] , size-bytecnt , 0);
bytecnt += recv(sock , buffer , size-bytecnt , MSG_WAITALL);
}
unsigned int test;
test = buffer[0];
cout << "value=" << test << "¤" << endl;
}
I took the pointer to the beginning of the buffer and cast it to uint32_t, but the result is completely wrong (I know it should be packet length, but it goes into millions of millions easily)
When I use the nl command: nc -l 12354 I can write text to my program and everything is correct
EDIT: Had a meeting with someone more experienced: SOLVED: I can't post solution myself, so I'll put it in here in case someone encounters a similar problem.
First of all, I expected the socket to be automatically handling where is a single transmission begin and where is its end - which is not true, as Basyle Starynkevitch pointed. However, the TCP ensures the data is coming in sequence and nothing is lost so I can safely assume that for 500 bytes promised I will get that 500 bytes or whatever it is.
Secondly, the data is coming in in the big endian - also as pointed by Basyle. I did a bit of bit shifting but still had a wrong result but...
Finally, I had another problem with type casting. I was using char* while the data is an unsigned char. Replacing buffers char* with unsigned char* solved the decoding issue.
This can be solution for anyone who gets to interface with old electronic devics that communicate over the local area network.
I guess this case can be considered closed if someone posts what I wrote above in a neat form.
recv
can fail with a negativebytecnt
– Basile Starynkevitch