2

I am a beginner and I am trying to feed a struct table with 4 members typed BIN with a pointer, then send them to another one, serial2. I fail to do so.

I receive 4 chars from serial1.read(), for example 'A' '10' '5' '3'. To decrease the size of the data, I want to use a struct:

struct structTable {
  unsigned int page:1; // (0,1)
  unsigned int cric:4; // 10 choices (4 bits)
  unsigned int crac:3; // 5 choices (3 bits)
  unsigned int croc:2; // 3 choices (2 bits)
};

I declare and set: instance and pointer

struct structTable structTable;
struct structTable *PtrstructTable; 
PtrstructTable = &structTable;

Then I try to feed like this:

for(int i = 0; i<=4; i++) {
  if(i == 1) {
    (*PtrProgs).page = Serial.read();
  if(i == 2) {
    (*PtrProgs).cric = Serial.read();

And so on. But it's not working...

I tried to feed a first char table and tried to cast the result:

(*PtrProgs).page = PtrT[1], BIN;

And now, I realize I can not feed 3 bits in one time! doh! All this seems very weak, and certainly a too long process for just 4 values. (I wanted to keep this kind of struct table for more instances).

Please, could you help me to find a simpler way to feed my table?

dda
  • 6,030
  • 2
  • 25
  • 34
patatos
  • 23
  • 1
  • 8

2 Answers2

2

You can only send full bytes over the serial port. But you can also send raw data directly.

void send (const structTable* table)
{
    Serial.write((const char*)table, sizeof(structTable));  // 2 bytes.
}

bool receive(structTable* table)
{
    return (Serial.readBytes((char*)table, sizeof(structTable)) == sizeof(structTable));
}

You also have to be aware that sizeof(int) is not the same on all CPUS

A word about endianness. The definition for your struct for the program at the other end of the serial link, if running on a CPU with a different endianness would become:

struct structTable {
  unsigned short int croc:2; // 3 choices (2 bits)
  unsigned short int crac:3; // 5 choices (3 bits)
  unsigned short int cric:4; // 10 choices (4 bits)
  unsigned short int page:1; // (0,1)
};

Note the use of short int, which you can also use in the arduino code to be more precise. The reason is that short int is 16 bits on most CPUs, while int may be 16,32 or even 64 bits.

Michaël Roy
  • 6,338
  • 1
  • 15
  • 19
  • thank you much Michael Roy. I will try this and ask a new question that follow this post. – patatos Aug 10 '17 at 15:18
  • Just make sure you use the same packed struct in the program at the other end to send/receive data. This way of sending/receiving data is very common, This is the same technique used by the IP stack, for example.. – Michaël Roy Aug 10 '17 at 15:30
1

According to the Arduino reference I just looked up Serial::read, the code returns data byte-by-byte (eight bits at a time). So probably you should just read the data one byte (eight bits at a time) and do your unpacking after the fact.

In fact you might want to use a union (see e.g. this other stackoverflow post on how to use a union) so that you can get the best of both worlds. Specifically, if you define a union of your definition with the bits broken out and a second part of the union as one or two bytes, you can send the data as bytes and then decode it in the bits you are interested in.

UPDATE

Here is an attempt at some more details. There are a lot of caveats about unions - they aren't portable, they are compiler dependent, etc. But this might be worth trying.

typedef struct {
  unsigned int page:1; // (0,1)
  unsigned int cric:4; // 10 choices (4 bits)
  unsigned int crac:3; // 5 choices (3 bits)
  unsigned int croc:2; // 3 choices (2 bits)
} structTable;

typedef union {
  structTable a;
  uint16_t b;
} u_structTable;

serial.Read(val1);
serial.Read(val2);

u_structTable x;
x.b = val1 | (val2<<8);
printf("page is %d\n", x.a.page);
Sol Arnu
  • 317
  • 4
  • 16
  • I actually reading data byte-by-byte from the serial. But precisely, I would like to send the 4 bytes to the next serial (no choice for serial), and keep a trace of thoses informations in tables (10 maybe)... sketch is following – patatos Aug 09 '17 at 22:21
  • so since you have 10 bits, write it as two bytes with a union and read it that way. – Sol Arnu Aug 09 '17 at 22:23
  • Thank you for your answer. however, I would like to keep as minimum possible size of the members, and this is why I try to stick to bits. – patatos Aug 09 '17 at 22:27
  • ok, well, good luck! trying to do something not aligned to byte boundaries is quite tricky. – Sol Arnu Aug 09 '17 at 22:31
  • now I am more interested. Please would you mind to precise your formulation – patatos Aug 09 '17 at 22:37
  • do the details i added help? Or what were you looking for? – Sol Arnu Aug 09 '17 at 22:41
  • "doing something not aligned to byte boundaries". I am sorry I don't understand this point, and I would like you precise this point. If that is possible. – patatos Aug 09 '17 at 22:44
  • Ah, I just mean if you want to store an array of your `structTable` then it is hard to do that without wasting the extra six bits (from 10->16 bits). Most computer architectures are pretty inefficient at accessing non-aligned data. – Sol Arnu Aug 09 '17 at 22:45
  • thank you. this is why I am confuse in the process. should (if possible) to cast the char (in hex) to a struct in my union, then write in struct of bit? – patatos Aug 09 '17 at 22:52
  • Probably the other answer is more elegant! – Sol Arnu Aug 10 '17 at 14:41
  • right now I am on the fog for this process, please, which answer you are talking about? thank you – patatos Aug 10 '17 at 14:57
  • Thank you for your good help Sol Arnu, It seems I cannot post the result of your code, so I will ask a new question that follow this thread. Thank you – patatos Aug 10 '17 at 15:20
  • "From Sol Arnu: I just mean if you want to store an array of your structTable then it is hard to do that without wasting the extra six bits (from 10->16 bits)". Why a table could not be considered as slignment of strings in the table and just take each adress folling each other? Thank you – patatos Aug 11 '17 at 20:16