hey guys i trying to write a handler for a generalised master/slave communication.
The implementation should be able to handle different communication types (USB/modbus/SPI etc.)
For every communication type a new instance of this class is created.
Each communication way has another max datalength limit. Every received packed (byte array) is mapped on a struct
class My_Communication
{
struct My_Struct
{
//some Header Information
byte data[max_data_length]; ///< this array has a different datalength.
}
}
Can i set the (const) datalength within a class constructor?
If you don't know the array size at compile time you should use std::vector:
class My_Communication
{
struct My_Struct
{
//some Header Information
std::vector< byte > data;
};
};
If you know the size at compile time then use std::array in a templated class:
class My_Communication
{
template < size_t DataSize >
struct My_Struct
{
//some Header Information
std::array< byte, DataSize > data;
};
};
Related
I have a SPI test class which I am trying to make flexible specially for user to be able to change\set the size of the Tx and Rx buffers which are private members of SpiTest class.
I have tried few ways by const_cast etc., but compiler keeps giving different sort of errors each time.
What would be best way to make my SpiTest class flexible enough to provide user a function which can be used to change the size of the buffer or may be just set a size of the buffer once but by client/user. Even once after creating test object to initialize size will be good enough.
Any ideas will be highly appreciated.
I have tried
Using Tx_size member as static then it complains about constness
1b- making Tx_size const complains about setting size is not possible using SetTxSize() method.
Initialising it in constructor not advantage.
Applying const_cast but that is only applicable to change pointer types consts
This is my class:
class SPITest
{
public:
SPITest();
~SPITest() = default;
uint8_t* GetTxBuf(void)
{
return &TX_m[0];
}
uint8_t* GetRxBuf(void)
{
return &RX_m[0];
}
uint8_t GetTxSize(void)
{
return Tx_Size;
}
void SetTxSize(uint8_t size)
{
Tx_Size= (size);
}
private:
static uint8_t Tx_Size = 6;
uint8_t TX_m[Tx_Size];
uint8_t RX_m[Tx_Size];
};
Errors are as follows:
Error[Pe1592]: a member with an in-class initializer must be const
Error[Pe028]: expression must have a constant value
Use a vector
Use a std::vector instead - a vector is a dynamic array.
Your class then becomes:
#include <vector>
class SPITest
{
public:
//...
void SetTxSize(size_t size)
{
TX_m.resize(size);
}
private:
std::vector<uint8_t> TX_m;
std::vector<uint8_t> RX_m;
};
is it at all possible in a reasonable way without hacks to define the size of an object array in a class without making the array size static. eg.
class Byte_Buffer
{
Byte_Buffer(uint16_t bs) : buf_size(bs) {}
const uint16_t buf_size;
uint8_t storage[ buf_size ];
};
template < int ARRAY_LEN > // you can even set to a default value here of C++'11
class MyClass
{
int array[ARRAY_LEN]; // Don't need to alloc or dealloc in structure! Works like you imagine!
}
// Then you set the length of each object where you declare the object, e.g.
MyClass<1024> instance; // But only works for constant values, i.e. known to compiler
I am using a third party library (mavlink) that defines a number of structs that are all tagged with __attribute__((packed)) so they can be efficiently be transmitted across a serial connection (it is written in C and I am using it in a C++ application). When I receive and reconstruct them I would like to add a time stamp field to them. I think the simplest way is to create a new struct that inherits the existing struct. i.e. in the mavlink library this struct is defined:
MAVPACKED(
typedef struct __mavlink_heartbeat_t {
uint32_t custom_mode;
uint8_t type;
uint8_t autopilot;
uint8_t base_mode;
uint8_t system_status;
uint8_t mavlink_version;
}) mavlink_heartbeat_t;
where MAVPACKED is a macro that applies __attribute__((packed)). sizeof(mavlink_heartbeat_t) returns 9. If I define
struct new_heartbeat_t : mavlink_heartbeat_t
{
uint64_t timestamp;
};
sizeof(new_heartbeat_t) returns 24, so it looks like 7 padding bytes are added (I would assume to end of mavlink_heartbeat_t so that timestamp start at byte 16.)
Are there any gotchas or things to be aware of when doing this or is there a better way?
Inheritance is a is a kind of relationship.
Is the local representation of a heartbeat really a kind of wire message? I doubt it.
But it might reasonably contain one.
I would encapsulate it something like this:
#include <cstdint>
#include <cstddef>
typedef struct __attribute__((packed)) __mavlink_heartbeat_t {
uint32_t custom_mode;
uint8_t type;
uint8_t autopilot;
uint8_t base_mode;
uint8_t system_status;
uint8_t mavlink_version;
} mavlink_heartbeat_t;
extern std::uint64_t now();
void sync_fetch_data(mavlink_heartbeat_t&);
void foo(uint8_t);
struct local_heartbeat
{
mavlink_heartbeat_t const& get_io_buffer() const {
return io_buffer_;
}
mavlink_heartbeat_t& prepare_receive() {
request_timestamp_ = now();
return io_buffer_;
}
void complete_receive() {
response_timestamp_ = now();
}
std::uint64_t get_response_timestamp() const {
return response_timestamp_;
}
private:
// stuff in here might have suspect alignment
mavlink_heartbeat_t io_buffer_;
// but these will be aligned for optimal performance
std::uint64_t request_timestamp_;
std::uint64_t response_timestamp_;
};
int main()
{
// create my local representation
local_heartbeat hb;
// prepare it to receive data
auto& buffer = hb.prepare_receive();
// somehow populate the buffer
sync_fetch_data(buffer); // could be async, etc
// notify the object that reception is complete
hb.complete_receive();
// now use the local representation
foo(hb.get_io_buffer().system_status);
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I'm trying to create an ethernet packet plus TCP/IP payload, for that I've create three structs as follows: ethernet struct, tcp struct and ip struct all these structs are filled with valid information but I don't know what I need to do now, I need join the spared structs into a plain struct (such as an array) since I want to inject the constructed packet and all bits need to be consecutive.
Define a new class, make these three structs its instance variables, code setters and getters for the class. You may want to pay attention to const correctness when writing getters - mark getters with const keyword.
struct EthStruct1
{
// ...
};
struct EthStruct2
{
// ...
};
struct EthStruct3
{
// ...
}
class newClass
{
public :
newClass(){}
~newClass(){}
// Add functions to get and set values in A. Mark getters with const for immutability of receiver
// Add functions to get and set values in B. Mark getters with const for immutability of receiver
// Add functions to get and set values in C. Mark getters with const for immutability of receiver
private:
EthStruct1 A;
EthStruct2 B;
EthStruct3 C;
};
Declare a byte array whose size is the sum of the sizes of the three structs. Then copy the raw bytes of each struct into the array where needed. Then use the array as needed.
struct ethernet
{
...
};
struct tcp
{
...
};
struct ip
{
...
};
ethernet e;
tcp t;
ip i;
unsigned char arr[sizeof(e)+sizeof(t)+sizeof(i)];
memcpy(&arr[0], &e, sizeof(e)];
memcpy(&arr[sizeof(e)], &t, sizeof(t)];
memcpy(&arr[sizeof(e)+sizeof(t)], &i, sizeof(i)];
Alternatively:
struct ethernet
{
...
};
struct tcp
{
...
};
struct ip
{
...
};
struct pkt
{
ethernet e;
tcp t;
ip i;
};
ethernet e;
tcp t;
ip i;
unsigned char arr[sizeof(pkt)];
pkt *p = (pkt) &arr[0];
p->e = e;
p->t = t;
p->i = i;
I like to use union when converting structures to byte arrays. Be sure your compiler is using single-byte structure alignment... for the Windows compiler I know you can use #pragma pack(push,1) to start that and #pragma pack(pop) to terminate. I will use this way in my example.
#pragma pack(push,1) // start single-byte struct alignment
struct EthernetInfo
{
// data here
};
struct TCPInfo
{
// data here
};
struct IPInfo
{
// data here
};
union Packet
{
struct {
struct EthernetInfo ethernetInfo;
struct TCPInfo tcpInfo;
struct IPInfo ipInfo;
} AsPacket;
unsigned char AsBytes[sizeof(EthernetInfo) + sizeof(TCPInfo) + sizeof(IPInfo)];
};
#pragma pack(pop) // revert to whatever struct alignment was in use before
I got a codebase which used to transfer several kinds of message on socket to another process and used a union for that
#define maxlen 60
typedef struct
{
TYRES t[MAXLEN];
} TYRE_T;
typdef struct
{
TUBES t[MAXLEN];
}TUBES_T;
typedef struct
{
TYPE t[MAXLEN];
} TYPE_T;
typedef union
{
TYRE_T tyres;
TUBES_T tubes;
TYPE_T type;
} messageunion;
typedef struct
{
int code;
messageunion msg;
} socketmessage_t;
enum msgtype
{
INVALID = -1;
TYRES,
TUBES,
TYPES
};
//On clientside
processMessage(socketmessage_t* msg)
{
switch(msg->code)
{
....
}
}
Now MAXLEN is not a macro but it will be run time variable evaluated by program. so I changed all array members to flexible array like this
typedef struct
{
int size;
TYRES t[];
}
My question is almost all socket functions needs size of buffer to receive message so how to calculate that size here?
Thanks
First you should probably start using fixed-size integers, like uint32_t (from <cstdint>) for the sizes and message types.
Then the receiving application know how much to read to get the message type, and how much to read to get the size. Then simply read the specified number of bytes into the correct structure.
The important thing is that all structures in the union must start with a size member.