Go Down

Topic: Problem sending struct by eth shield (Read 1 time) previous topic - next topic

ramo102

Hi all!
I have a problem sending a C struct from my Arduino Uno to my notebook.

If I try to send the structure from a C client, it works flawlessy.
Trying to send the same identical structure from the arduino sketch results in a buggy output.

Here's the code.

Arduino sketch:
Code: [Select]

#include <stdint.h>
#include <SPI.h>
#include <Ethernet.h>

void send_mystruct(struct mystruct *);
mystruct * create_mystruct();

void print_mystruct(mystruct);
void print_nadd(mystruct *);
void print_xadd(mystruct *);


#pragma pack(1)
struct mystruct {
 unsigned char type:4;
 unsigned int len:12;
 uint8_t value;
 uint8_t nadd[2];
 uint8_t xadd[8];
 uint64_t id;
 uint8_t sum;
};

typedef struct mystruct mystruct;

byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 192, 168, 33, 17 };
byte gateway[] = { 192, 168, 33, 13 };
byte server[] = { 192, 168, 33, 16 };  // notebook

uint8_t xa[8] = { 0xc, 0xd, 0xe, 0xf, 0x0, 0x1, 0x2, 0x3 };
uint8_t na[2] = { 0xa, 0xb };

Client client(server, 10001);

mystruct *h = NULL;

void setup() {
 Ethernet.begin(mac, ip, gateway);
 delay(1000);
 Serial.begin(9600);
 
 h = create_mystruct();
 mystruct_set_nadd(h, na);
 mystruct_set_xadd(h, xa);
 
 if (h) {
   print_mystruct(h);
 }
 
 Serial.println();
 if (client.connect()) {    
   Serial.println("connected");
   if (h)  send_mystruct(h);        
 }
 else {
   Serial.println("connection failed");
 }  
}

void loop () {
 
 if (!client.connected()) {
   Serial.println();
   Serial.println("disconnecting.");
   client.stop();

   for(;;)
     ;
 }
}

void send_mystruct(struct mystruct *head) {
 
 if (head) {
//    client.println(head);
   client.println((const char *) head);
 }
}

void print_mystruct(mystruct *h) {

 if (h) {
   Serial.println("Header fields:");
   Serial.print("Type = ");
   Serial.println(h->type, DEC);
   Serial.print("Len = ");
   Serial.println(h->len, DEC);
   Serial.print("IP = ");
   Serial.println(h->value, DEC);
   Serial.print("Network address = ");
   print_nadd(h);
   Serial.print("XBee address = ");
   print_xadd(h);
   Serial.print("id = ");  
   Serial.println((long) h->id);
   Serial.print("Checksum = ");
   Serial.println(h->sum, DEC);
 }
}


void print_nadd(mystruct *h) {  
 if (!h)  return;
 
 uint8_t *na = h->nadd;
 
 Serial.print("{ ");
 for (int i = 0; i < 2; i++) {
   Serial.print(na[i], DEC);
   Serial.print(" ");
 }
 Serial.println("} ");
}

void print_xadd(mystruct *h) {  
 if (!h)  return;
 
 uint8_t *xa = h->xadd;
 
 Serial.print("{ ");
 for (int i = 0; i < 8; i++) {
   Serial.print(xa[i], DEC);
   Serial.print(" ");
 }
 Serial.println("} ");
}

mystruct * create_mystruct() {
 
 mystruct *h = NULL;
 h = (mystruct *) malloc(sizeof(mystruct));
 
 if (h) {  
   h->len = 57;
   h->type = 2;
   h->value = 15;
   h->sum = 99;
   h->id = 1299;
   mystruct_set_nadd(h, na);
   mystruct_set_xadd(h, na);
 }  
 return h;
}
 
void mystruct_set_nadd(mystruct *h, uint8_t *net) {
 if (h) {
   for (int i = 0; i < 2; i++) {
     h->nadd[i] = net[i];
   }
 }
}
 
void mystruct_set_xadd(mystruct *h, uint8_t *xbee) {
 if (h) {
   for (int i = 0; i < 8; i++) {
     h->xadd[i] = xbee[i];
   }
 }
}


C server:
Code: [Select]

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#pragma pack(1)
struct mystruct {
 unsigned char type:4;
 unsigned int len:12;
 uint8_t value;
 uint8_t nadd[2];
 uint8_t xadd[8];
 uint64_t id;
 uint8_t sum;
};
typedef struct mystruct mystruct;

const int STRUCT_LENGTH = 22;

mystruct * parse_mystruct(char *);
mystruct * mystruct_create(void);
void print_mystruct(mystruct *h);
void print_nadd(mystruct *h);
void print_xadd(mystruct *h);


void error(char *msg)
{
   perror(msg);
   exit(1);
}

int main(int argc, char *argv[])
{
    int sockfd, newsockfd, portno, clilen;
    char *buffer = NULL;
    struct sockaddr_in serv_addr, cli_addr;
    int n;
    mystruct *h = NULL;

    if (argc < 2) {
        fprintf(stderr,"ERROR, no port provided\n");
        exit(1);
    }
    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    if (sockfd < 0) {
       error("ERROR opening socket");
    }
    memset((char *) &serv_addr, 0, sizeof(serv_addr));
    portno = atoi(argv[1]);
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(portno);

    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
       error("ERROR on binding");
    }
    listen(sockfd, 5);
    clilen = sizeof(cli_addr);
    newsockfd = accept(sockfd,
                (struct sockaddr *) &cli_addr,
                (socklen_t *) &clilen);

    if (newsockfd < 0) {
       error("ERROR on accept");
    }

    buffer = (char *) malloc(sizeof(char) * STRUCT_LENGTH);
    memset(buffer, 0, STRUCT_LENGTH);
   
    n = read(newsockfd, buffer, STRUCT_LENGTH);
    if (n < 0) {
       error("ERROR reading from socket");
    }
    h = parse_mystruct(buffer);

    if (h)
        print_mystruct(h);

    return 0;
}

mystruct * parse_mystruct(char *buf) {
   mystruct *tmp = NULL;

   if (!buf)
       return NULL;

   tmp = mystruct_create();
   if (tmp) {
       memcpy(tmp, buf, STRUCT_LENGTH);
   }
   return tmp;
}

mystruct * mystruct_create() {
   mystruct *tmp = NULL;

   tmp = (mystruct *) malloc(sizeof(mystruct));
   if (tmp) {
       memset(tmp, 0, sizeof(mystruct));
       tmp->type = 1;
       tmp->value = 9;
       tmp->id = (uint64_t) time(NULL);
   }
   return tmp;
}

void print_mystruct(mystruct *h) {
   if (h) {
       printf("Header fields:\n");
       printf("type = %d\n", h->type);
       printf("len = %d\n", h->len);
       printf("ip = %d\n", h->value);
       printf("net address = ");
       print_nadd(h);
       printf("xbee address = ");
       print_xadd(h);
       printf("id = %lu\n", h->id);
       printf("sum = %d\n", h->sum);
   }
}

void print_nadd(mystruct *h) {
   int i;
   uint8_t *na = h->nadd;

   if (h) {
       for (i = 0; i < 2; i ++) {
           printf(" %d ", na[i]);
       }
       printf("\n");
   }
}

void print_xadd(mystruct *h) {
   int i;
   uint8_t *xa = h->xadd;

   if (h) {
       for (i = 0; i < 8; i ++) {
           printf(" %d ", xa[i]);
       }
       printf("\n");
   }
}


Here's the arduino (correct) output:

Header fields:
Type = 2
Len = 57
IP = 15
Network address = { 10 11 }
XBee address = { 12 13 14 15 0 1 2 3 }
id = 1299
Checksum = 99


And here's the server (uncorrect) output:

Header fields:
type = 2
len = 57
ip = 15
net address =  10  11
xbee address =  12  13  14  15  0  0  0  0
id = 0
sum = 0


Any help will be really appreciated.

ramo102

I also post the differences from gdb.

C client:
Code: [Select]

(gdb) p buffer
$1 = 0x804a008 "\222\003\017\n\v\f\r\016\017"
(gdb) x/22bt 0x804a008
0x804a008:      10010010      00000011      00001111      00001010      00001011      00001100      00001101      00001110
0x804a010:      00001111      00000000      00000001      00000010      00000011      00010011      00000101      00000000
0x804a018:      00000000      00000000      00000000      00000000      00000000      01100011


Header fields:
type = 2
len = 57
ip = 15
net address =  10  11
xbee address =  12  13  14  15  0  1  2  3
id = 1299
sum = 99


Arduino client:
Code: [Select]

(gdb) p buffer
$2 = 0x804a008 "\222\003\017\n\v\f\r\016\017\r\n"
(gdb) x/22bt 0x804a008
0x804a008:      10010010      00000011      00001111      00001010      00001011      00001100      00001101      00001110
0x804a010:      00001111      00001101      00001010      00000000      00000000      00000000      00000000      00000000
0x804a018:      00000000      00000000      00000000      00000000      00000000      00000000


Header fields:
type = 2
len = 57
ip = 15
net address =  10  11
xbee address =  12  13  14  15  0  0  0  0
id = 0
sum = 0

I may be wrong... but if I got my maths right, your struct length in the server side is wrong.

Then, what does this "unsigned char type:4;" do? The :4 part... I've never seen it before.

Is the uint8_t different from char in size? if not, I count 23 and not 22 as the size of the struct.

Have you tried sizeof()? After all, the structure is static.
Eu não sou o teu criado. Se respondo no fórum é para ajudar todos mediante a minha disponibilidade e disposição. Responder por mensagem pessoal iria contra o propósito do fórum e por isso evito-o.
Se realmente pretendes que eu te ajude por mensagem pessoal, então podemos chegar a um acordo e contrato onde me pagas pela ajuda que eu fornecer e poderás então definir os termos de confidencialidade do meu serviço. De forma contrária toda e qualquer ajuda que eu der tem de ser visível a todos os participantes do fórum (será boa ideia, veres o significado da palavra fórum).
Nota também que eu não me responsabilizo por parvoíces escritas neste espaço pelo que se vais seguir algo dito por mim, entende que o farás por tua conta e risco.

Dito isto, mensagens pessoais só se forem pessoais, ou seja, se já interagimos de alguma forma no passado ou se me pretendes convidar para uma churrascada com cerveja (paga por ti, obviamente).

ramo102

Structure size is correct.

The ":4" after the variable name represents a bit field.

"p sizeof(mystruct)" from inside gdb gives me 22, as expected.

And above all, the same program works pretty if input arrives from my pc instead.

I'm not the best in Arduino language, but how is this supposed to work?

As I read it, you check if there's some connection waiting on startup and if not the program doesn't do anything. am I right?

The only thing I'm thinking is if you disconnect the connection before data is sent. It doesn't look like it with the way you wrote it, but I believe the Ethernet is implemented as a buffer... I'm almost 100% this isn't the problem, but just to check it, try adding a somewhat big delay after printing the structure.

Apart from that I have no idea what's going on. :S
Eu não sou o teu criado. Se respondo no fórum é para ajudar todos mediante a minha disponibilidade e disposição. Responder por mensagem pessoal iria contra o propósito do fórum e por isso evito-o.
Se realmente pretendes que eu te ajude por mensagem pessoal, então podemos chegar a um acordo e contrato onde me pagas pela ajuda que eu fornecer e poderás então definir os termos de confidencialidade do meu serviço. De forma contrária toda e qualquer ajuda que eu der tem de ser visível a todos os participantes do fórum (será boa ideia, veres o significado da palavra fórum).
Nota também que eu não me responsabilizo por parvoíces escritas neste espaço pelo que se vais seguir algo dito por mim, entende que o farás por tua conta e risco.

Dito isto, mensagens pessoais só se forem pessoais, ou seja, se já interagimos de alguma forma no passado ou se me pretendes convidar para uma churrascada com cerveja (paga por ti, obviamente).

westfw

Both structures and (especially) bitfields are "implementation dependent" in C, and not guaranteed to transport between architectures.  However, it doesn't look like you are having the usual sort of packing or endianness issues.  It looks more like a packet-size thing where the arduino is perhaps sending more than one packet and the read on the server side is only reading one packet at a time.  You should have your read code confirm that you are reading the entire structure:
Code: [Select]
    n = read(newsockfd, buffer, STRUCT_LENGTH);
    if (n < 0) {
       error("ERROR reading from socket");
    }
   // added code:
    if (n < STRUCT_LENGTH) {
      error("partial structure read");
    }


ramo102

I tried the code from westfw, and saw that he's right.

The server only receives 9-10 bytes (11, sometimes).

Do someone knows why this happens?
And is there a way to make sure that the server receives all the packets?

PaulS

You are using Client.println() to send the structure, that you have cast to a char * pointer. The println function stops printing when it finds the first 0 embedded in the structure, which occurs in the 4th element of the xa array.

ramo102

Quote
The println function stops printing when it finds the first 0 embedded in the structure, which occurs in the 4th element of the xa array.

But why it sometimes read nine bytes, and sometimes ten? Naturally, it can always stop at the 9th byte.

I substitute the Client.println() line with the following:
Code: [Select]
for (int i = 0; i < sizeof(mystruct); i++) {
     client.write((char *) head++);
   }

and made some tests.

Here the tests I made:
- running server normally -> only 9 bytes readed
- running server in debug mode -> it receives all the 22 bytes, but there are strange results after the 9th byte:

(gdb) p buffer
$5 = 0x804a008 "\222\003\017\n\v\f\r\016\017\366\335\307=\177\272\247\332\313\325\356\377", <incomplete sequence \375>

Header fields:
type = 2
len = 57
ip = 15
net address =  10  11
xbee address =  12  13  14  15  246  221  199  61
id = 3668425343
sum = 253

- running server normally, with a sleep(1) inserted before the n = read(newsockfd, buffer, STRUCT_LENGTH); line -> the same result as the second case.
[/list]

ramo102

#9
Jan 17, 2011, 04:22 pm Last Edit: May 29, 2011, 06:00 pm by ramo102 Reason: 1
I found the right solution to this problem.

The following function:

Code: [Select]

void send_mystruct(struct mystruct *head) {
 
  if (head) {
//    client.println(head);
    client.println((const char *) head);
  }
}


Must become:
Code: [Select]

void send_mystruct(struct mystruct *head) {
 
  byte *ptr = (byte *) head;
 
  if (head) {
    for (int i = 0; i < sizeof(mystruct); i++) {
      client.write(*ptr++);
    }
  }
}

so all the structure's bytes arrive can be correctly decoded from the server.

Go Up