Arduino - how to feed a struct from a serial.read()? - c++

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?

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.

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

Related

I want to toggle the bits of the given offset

I want to toggle a bit at a given 'offset', I have tried by using typedef to create a new type as "BYTEBUF" and its variable as bitstream.
...
typedef struct{
char *data;
unsigned int nb_bytes;
unsigned long bitlength;
}BYTEBUF;
this is my typedefinition
i want to toggle the bit at a given offset,
i tried using :
bitstream->data[offset]^=1
but many suggest that instead of "offset" it should be "offset/8".
(this is my first question so pls bare for any mistakes)
You can simply use the std::bitset class from the std which offers you all the tools you need for manipulating bits. In your case you would use it like this:
// A array of bits of size 16
std::bitset<16> bits;
// Flip the 6th bit
bits.flip(5);
// Set the 6th bit to one
bits.set(5, true);
If you need to have a struct of variable size (which in your example is the case) then you could do something like this:
struct BYTES
{
char* bytes;
// Toggle the byte at position
// Note that I'm not checking for any overflow
// which you should definitely do
void toggle(const size_t position)
{
bytes[position/8] ^= 1 << (position % 8);
}
};
// I'm assuming everything has been allocated properly
BYTES b;
// Toggle the 14th bit
b.toggle(14);
The position/8 gives you the index in the array (as it is an array of char) and position%8 gives you the offset for the single bit inside one char. I would strongly advice you do the arithmetic on a paper yourself to see the picture here!
If you want to toggle the bit corresponding to the integer offset, you can calculate:
int bytenum = (offset >> 3);
int bitnum = offset - (bytenum << 3);
Then assuming bitstream is of type BYTEBUF you can do:
bitstream.data[bytenum] ^= (1 << bitnum);
Obviously, you need to be careful that the bytenum is in range (within length of valid memory pointed to by data), that the object has been initialised/constructed properly, etc...

convert (n first bytes of) unsigned char pointer to float and double c++

Consider the following c++ code:
unsigned char* data = readData(..); //Let say data consist of 12 characters
unsigned int dataSize = getDataSize(...); //the size in byte of the data is also known (let say 12 bytes)
struct Position
{
float pos_x; //remember that float is 4 bytes
double pos_y; //remember that double is 8 bytes
}
Now I want to fill a Position variable/instance with data.
Position pos;
pos.pos_x = ? //data[0:4[ The first 4 bytes of data should be set to pos_x, since pos_x is of type float which is 4 bytes
pos.pos_x = ? //data[4:12[ The remaining 8 bytes of data should be set to pos_y which is of type double (8 bytes)
I know that in data, the first bytes correspond to pos_x and the rest to pos_y. That means the 4 first byte/character of data should be used to fill pos_x and the 8 remaining byte fill pos_y but I don't know how to do that.
Any idea? Thanks. Ps: I'm limited to c++11
You can use plain memcpy as another answer advises. I suggest packing memcpy into a function that also does error checking for you for most convenient and type-safe usage.
Example:
#include <cstring>
#include <stdexcept>
#include <type_traits>
struct ByteStreamReader {
unsigned char const* begin;
unsigned char const* const end;
template<class T>
operator T() {
static_assert(std::is_trivially_copyable<T>::value,
"The type you are using cannot be safely copied from bytes.");
if(end - begin < static_cast<decltype(end - begin)>(sizeof(T)))
throw std::runtime_error("ByteStreamReader");
T t;
std::memcpy(&t, begin, sizeof t);
begin += sizeof t;
return t;
}
};
struct Position {
float pos_x;
double pos_y;
};
int main() {
unsigned char data[12] = {};
unsigned dataSize = sizeof data;
ByteStreamReader reader{data, data + dataSize};
Position p;
p.pos_x = reader;
p.pos_y = reader;
}
One thing that you can do is to copy the data byte-by byte. There is a standard function to do that: std::memcpy. Example usage:
assert(sizeof pos.pos_x == 4);
std::memcpy(&pos.pos_x, data, 4);
assert(sizeof pos.pos_y == 8);
std::memcpy(&pos.pos_y, data + 4, 8);
Note that simply copying the data only works if the data is in the same representation as the CPU uses. Understand that different processors use different representations. Therefore, if your readData receives the data over the network for example, a simple copy is not a good idea. The least that you would have to do in such case is to possibly convert the endianness of the data to the native endianness (probably from big endian, which is conventionally used as the network endianness). Converting from one floating point representation to another is much trickier, but luckily IEE-754 is fairly ubiquitous.

Best way to pass variables between Arduino and PC over serial?

I've written an Arduino sketch which reads data from a remote control receiver and returns a value between 0 and 1023 for that channel. I basically want to send this data (something in the format of channel:value, eg, Channel 1 : 1023, Channel 2 : 511) to a PC program (which I plan to write myself).
The most efficient way I can think to do this is to use two bytes of data, with the first 6 bits representing the channel (2^6 = 64 possible channels, way more than I need), and the last ten representing the value (2^10 = 1024, perfect). But I'm not sure on the best way to implement this in C++, or if this is even the most ideal way to do this. So:
What is the best way to craft individual bytes and work with binary numbers in C++? Preferably storing the values in memory as such (ie, no bool arrays, where each index takes up it's own byte). Two bytes of data is more than enough for what I need.
Is this the easiest/simplest/most efficient/recommended way to implement what I am trying to achieve? I basically want to pass variables as is between programs, are there any other ways to do this?
You can declare a packed struct to hold these two values:
struct chan_value_t
{
uint8_t channel : 6;
uint16_t value : 10;
};
But to send it as two bytes, you'll need to either (1) "union" it with a two-byte array:
union chan_value_t
{
struct {
uint8_t channel : 6;
uint16_t value : 10;
};
uint8_t bytes[2];
};
chan_value_t cv;
void setup()
{
Serial.begin( 9600 );
cv.channel = 2;
cv.value = 800;
for (int i=0; i<sizeof(cv.bytes); i++) {
Serial.print( cv.bytes[i], HEX );
Serial.print( ' ' );
}
Serial.println();
}
void loop() {}
(The struct is anonymous when nested in this union; the union has the name.)
Or (2) cast a pointer to the struct to a pointer to bytes:
struct chan_value_t {
uint8_t channel : 6;
uint16_t value : 10;
};
chan_value_t cv;
void setup()
{
Serial.begin( 9600 );
cv.channel = 2;
cv.value = 800;
uint8_t *bytes = (uint8_t *) &cv; // cast &cv to a pointer to bytes
for (int i=0; i<sizeof(cv); i++) {
Serial.print( bytes[i], HEX );
Serial.print( ' ' );
}
Serial.println();
}
void loop() {}
They both print the hexadecimal value of the bytes: 0x02 and 0xC8. 800 is 0x320, shifted left by 6 bits is 0xC800.
To send this to the PC, you may want to start with a special character sequence and finish with a checksum of some sort (Fletcher checksum is easy). Then it's easy to throw away garbage characters and know when there are transmission errors.
This is aimed at your no. 2 question.
OSC (OpenSoundControl) is a convenient way to send messages across different platforms and devices. Libraries exist for most platforms.
You could use the library OSC for Arduino and implement your own solution to the specification or using a library that fits your context.
The message you mention could be sent as /channel/1 /value/1023

Parsing a binary message in C++. Any lib with examples?

I am looking for any library of example parsing a binary msg in C++. Most people asks for reading a binary file, or data received in a socket, but I just have a set of binary messages I need to decode. Somebody mentioned boost::spirit, but I haven't been able to find a suitable example for my needs.
As an example:
9A690C12E077033811FFDFFEF07F042C1CE0B704381E00B1FEFFF78004A92440
where first 8 bits are a preamble, next 6 bits the msg ID (an integer from 0 to 63), next 212 bits are data, and final 24 bits are a CRC24.
So in this case, msg 26, I have to get this data from the 212 data bits:
4 bits integer value
4 bits integer value
A 9 bit float value from 0 to 63.875, where LSB is 0.125
4 bits integer value
EDIT: I need to operate at bit level, so a memcpy is not a good solution, since it copies a number of bytes. To get first 4-bit integer value I should get 2 bits from a byte, and another 2 bits from the next byte, shift each pair and compose. What I am asking for is a more elegant way of extracting the values, because I have about 20 different messages and wanted to reach a common solution to parse them at bit level.
And so on.
Do you know os any library which can easily achieve this?
I also found other Q/A where static_cast is being used. I googled about it, and for each person recommending this approach, there is another one warning about endians. Since I already have my message, I don't know if such a warning applies to me, or is just for socket communications.
EDIT: boost:dynamic_bitset looks promising. Any help using it?
If you can't find a generic library to parse your data, use bitfields to get the data and memcpy() it into an variable of the struct. See the link Bitfields. This will be more streamlined towards your application.
Don't forget to pack the structure.
Example:
#pragma pack
include "order32.h"
struct yourfields{
#if O32_HOST_ORDER == O32_BIG_ENDIAN
unsigned int preamble:8;
unsigned int msgid:6;
unsigned data:212;
unsigned crc:24;
#else
unsigned crc:24;
unsigned data:212;
unsigned int msgid:6;
unsigned int preamble:8;
#endif
}/*__attribute__((packed)) for gcc*/;
You can do a little compile time check to assert if your machine uses LITTLE ENDIAN or BIG ENDIAN format. After that define it into a PREPROCESSOR SYMBOL::
//order32.h
#ifndef ORDER32_H
#define ORDER32_H
#include <limits.h>
#include <stdint.h>
#if CHAR_BIT != 8
#error "unsupported char size"
#endif
enum
{
O32_LITTLE_ENDIAN = 0x03020100ul,
O32_BIG_ENDIAN = 0x00010203ul,
O32_PDP_ENDIAN = 0x01000302ul
};
static const union { unsigned char bytes[4]; uint32_t value; } o32_host_order =
{ { 0, 1, 2, 3 } };
#define O32_HOST_ORDER (o32_host_order.value)
#endif
Thanks to code by Christoph # here
Example program for using bitfields and their outputs:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <memory.h>
using namespace std;
struct bitfields{
unsigned opcode:5;
unsigned info:3;
}__attribute__((packed));
struct bitfields opcodes;
/* info: 3bits; opcode: 5bits;*/
/* 001 10001 => 0x31*/
/* 010 10010 => 0x52*/
void set_data(unsigned char data)
{
memcpy(&opcodes,&data,sizeof(data));
}
void print_data()
{
cout << opcodes.opcode << ' ' << opcodes.info << endl;
}
int main(int argc, char *argv[])
{
set_data(0x31);
print_data(); //must print 17 1 on my little-endian machine
set_data(0x52);
print_data(); //must print 18 2
cout << sizeof(opcodes); //must print 1
return 0;
}
You can manipulate bits for your own, for example to parse 4 bit integer value do:
char[64] byte_data;
size_t readPos = 3; //any byte
int value = 0;
int bits_to_read = 4;
for (size_t i = 0; i < bits_to_read; ++i) {
value |= static_cast<unsigned char>(_data[readPos]) & ( 255 >> (7-i) );
}
Floats usually sent as string data:
std::string temp;
temp.assign(_data+readPos, 9);
flaot value = std::stof(temp);
If your data contains custom float format then just extract bits and do your math:
char[64] byte_data;
size_t readPos = 3; //any byte
float value = 0;
int i = 0;
int bits_to_read = 9;
while (bits_to_read) {
if (i > 8) {
++readPos;
i = 0;
}
const int bit = static_cast<unsigned char>(_data[readPos]) & ( 255 >> (7-i) );
//here your code
++i;
--bits_to_read;
}
Here is a good article that describes several solutions to the problem.
It even contains the reference to the ibstream class that the author created specifically for this purpose (the link seems dead, though). The only other mention of this class I could find is in the bit C++ library here - it might be what you need, though it's not popular and it's under GPL.
Anyway, the boost::dynamic_bitset might be the best choice as it's time-tested and community-proven. But I have no personal experience with it.

Getting the size of an indiviual field from a c++ struct field

The short version is: How do I learn the size (in bits) of an individual field of a c++ field?
To clarify, an example of the field I am talking about:
struct Test {
unsigned field1 : 4; // takes up 4 bits
unsigned field2 : 8; // 8 bits
unsigned field3 : 1; // 1 bit
unsigned field4 : 3; // 3 bits
unsigned field5 : 16; // 16 more to make it a 32 bit struct
int normal_member; // normal struct variable member, 4 bytes on my system
};
Test t;
t.field1 = 1;
t.field2 = 5;
// etc.
To get the size of the entire Test object is easy, we just say
sizeof(Test); // returns 8, for 8 bytes total size
We can get a normal struct member through
sizeof(((Test*)0)->normal_member); // returns 4 (on my system)
I would like to know how to get the size of an individual field, say Test::field4. The above example for a normal struct member does not work. Any ideas? Or does someone know a reason why it cannot work? I am fairly convinced that sizeof will not be of help since it only returns size in bytes, but if anyone knows otherwise I'm all ears.
Thanks!
You can calculate the size at run time, fwiw, e.g.:
//instantiate
Test t;
//fill all bits in the field
t.field1 = ~0;
//extract to unsigned integer
unsigned int i = t.field1;
... TODO use contents of i to calculate the bit-width of the field ...
You cannot take the sizeof a bitfield and get the number of bits.
Your best bet would be use #defines or enums:
struct Test {
enum Sizes {
sizeof_field1 = 4,
sizeof_field2 = 8,
sizeof_field3 = 1,
sizeof_field4 = 3,
sizeof_field5 = 16,
};
unsigned field1 : sizeof_field1; // takes up 4 bits
unsigned field2 : sizeof_field2; // 8 bits
unsigned field3 : sizeof_field3; // 1 bit
unsigned field4 : sizeof_field4; // 3 bits
unsigned field5 : sizeof_field5; // 16 more to make it a 32 bit struct
int normal_member; // normal struct variable member, 4 bytes on my system
};
printf("%d\n", Test::sizeof_field1); // prints 4
For the sake of consistency, I believe you can move normal_member up to the top and add an entry in Sizes using sizeof(normal_member). This messes with the order of your data, though.
Seems unlikely, since sizeof() is in bytes, and you want bits.
http://en.wikipedia.org/wiki/Sizeof
building on the bit counting answer, you can use.
http://www-graphics.stanford.edu/~seander/bithacks.html
Using ChrisW's idea (nice, by the way), you can create a helper macro:
#define SIZEOF_BITFIELD(class,member,out) { \
class tmp_; \
tmp_.member = ~0; \
unsigned int tmp2_ = tmp_.member; \
++tmp2_; \
out = log2(tmp2_); \
}
unsigned int log2(unsigned int x) {
// Overflow occured.
if(!x) {
return sizeof(unsigned int) * CHAR_BIT;
}
// Some bit twiddling... Exploiting the fact that floats use base 2 and store the exponent. Assumes 32-bit IEEE.
float f = (float)x;
return (*(unsigned int *)&f >> 23) - 0x7f;
}
Usage:
size_t size;
SIZEOF_BITFIELD(Test, field1, size); // Class of the field, field itself, output variable.
printf("%d\n", size); // Prints 4.
My attempts to use templated functions have failed. I'm not an expert on templates, however, so it may still be possible to have a clean method (e.g. sizeof_bitfield(Test::field1)).
I don't think you can do it. If you really need the size, I suggest you use a #define (or, better yet, if possible a const variable -- I'm not sure if that's legal) as so:
#define TEST_FIELD1_SIZE 4
struct Test {
unsigned field1 : TEST_FIELD1_SIZE;
...
}
This is not possible
Answer to comment:
Because the type is just an int, there is no 'bit' type. The bit field assignment syntax is just short hand for performing the bitwise code for reads and writes.