Pages: [1]   Go Down
Author Topic: Problem sending struct by eth shield  (Read 1570 times)
0 Members and 1 Guest are viewing this topic.
Italy
Offline Offline
Jr. Member
**
Karma: 0
Posts: 53
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
#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:
#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.
Logged

Italy
Offline Offline
Jr. Member
**
Karma: 0
Posts: 53
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I also post the differences from gdb.

C client:
Code:
(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:
(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
Logged

'round the world...
Online Online
Faraday Member
**
Karma: 42
Posts: 3285
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

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).

Italy
Offline Offline
Jr. Member
**
Karma: 0
Posts: 53
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

'round the world...
Online Online
Faraday Member
**
Karma: 42
Posts: 3285
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

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).

SF Bay Area (USA)
Offline Offline
Tesla Member
***
Karma: 135
Posts: 6782
Strongly opinionated, but not official!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
    n = read(newsockfd, buffer, STRUCT_LENGTH);
     if (n < 0) {
        error("ERROR reading from socket");
     }
    // added code:
     if (n < STRUCT_LENGTH) {
       error("partial structure read");
     }
Logged

Italy
Offline Offline
Jr. Member
**
Karma: 0
Posts: 53
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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?
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 631
Posts: 50111
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Italy
Offline Offline
Jr. Member
**
Karma: 0
Posts: 53
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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]
Logged

Italy
Offline Offline
Jr. Member
**
Karma: 0
Posts: 53
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I found the right solution to this problem.

The following function:

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

Must become:
Code:
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.
« Last Edit: May 29, 2011, 11:00:41 am by ramo102 » Logged

Pages: [1]   Go Up
Jump to: