Access struct elements in a class linitalizer list - c++

I'm working on an embedded-system project using EFM32GG11 series micro-controller. In project I've to read data from multiple serial port, process the data and forward the data to server via Ethernet.
I've created a class that will handle serial port. Multiple object of this class will be created.
I've created a constructor with initialize list. I've a question : Is their a way to directly access structure member in initialization list? - uart_init.baudRate(baud_rate)
class SerialPort {
public :
enum PortList{
COM1, //RS-232
COM2 //RS-232 -- 8 more ports
};
private:
PortList port_no;
UARTDRV_Init_t uart_init;
uint32_t baud_rate;
char parity;
uint8_t stop_bit;
bool single_line_mode;
uint16_t block_time; //in milli-seconds
public:
SerialPort(PortList port_no, uint16_t baud_rate, char parity, uint8_t stop_bit,
bool single_line_mode, uint16_t block_time) : port_no(port_no), uart_init.baudRate(baud_rate), parity(parity), stop_bit(stop_bit), single_line_mode(single_line_mode),
block_time(block_time)
{
//Further processing post initialization
}
};
UARTDRV_Init_t Strurcture :
typedef struct {
USART_TypeDef *port; ///< The peripheral used for UART
uint32_t baudRate; ///< UART baud rate
} UARTDRV_InitUart_t;

You can use designated initializers (since C++20) to specify the member to be initialized. E.g.
SerialPort(PortList port_no, uint16_t baud_rate, char parity, uint8_t stop_bit,
bool single_line_mode, uint16_t block_time) : port_no(port_no), uart_init {.baudRate=baud_rate}, parity(parity), stop_bit(stop_bit), single_line_mode(single_line_mode),
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
block_time(block_time)
{
//Further processing post initialization
}
Before C++17, we can only initialize the data member itself in member initializer list and can't specify its subobject further more.

If you know the what the default for port should be, you could do it this way, assuming port is initialized to nullptr or something:
SerialPort(PortList port_no, uint16_t baud_rate, char parity, uint8_t stop_bit,
bool single_line_mode, uint16_t block_time) : port_no(port_no), uart_init {nullptr, baud_rate}, parity(parity), stop_bit(stop_bit), single_line_mode(single_line_mode),
block_time(block_time)
{
...
}

Related

Scope and Usage of Nested Classes

I'm writing some code that interfaces with a GPS receiver and I'm trying to understand if the way I'm attempting to implement it is possible and if so how to do it.
The GPS communicates with an Arduino via I2C and I want to have a single object that handles all of the GPS interface commands. The basic structure is as follows:
Header File (Simplified)
//UBLOX.h
class UBLOX_INTERFACE
{
private:
const uint8_t i2cAddress;
public:
UBLOX_INTERFACE(uint8_t address);
class NMEA
{
private:
void intakeNMEA(); //This function needs access to UBLOX_INTERFACE::i2cAddress
//Other local variables and functions
};
class UBX_COMMS
{
private:
uint8_t prepAndSendPacket(uint8_t packet[], const uint16_t packetLength);
public:
UBX_COMMS(uint8_t ubxclass, uint8_t id, uint8_t length0, uint8_t length1);
};
class UBX_CFG_RATE : public UBX_COMMS
{
using UBX_COMMS::UBX_COMMS;
private:
public:
bool set(const uint16_t GNSSmeasureRate); // Sets GNSS measurement rate
void poll();
};
class UBX_CFG_RST : public UBX_COMMS
{
using UBX_COMMS::UBX_COMMS;
private:
public:
bool gnssReset(const uint8_t navBbrMask);
bool hardwareReset(const uint8_t resetMode);
};
}
CPP File (Simplified)
//UBLOX.cpp
#include "UBLOX.h"
//UBLOX_INTERFACE Class Functions
UBLOX_INTERFACE::UBLOX_INTERFACE(uint8_t address): i2cAddress(address)
{
NMEA nmea;
UBX_CFG_RATE ubxCFG_RATE(0x06, 0x08, 0, 6); //These values are permanently defined constants for each command type
UBX_CFG_RST ubxCFG_RST(0x06, 0x04, 0, 4);
}
//NMEA Class Functions
void UBLOX_INTERFACE::NMEA::intakeNMEA()
{
Wire.beginTransmission(i2cAddress); //This line has a compile error: invalid use of non-static data member 'UBLOX_INTERFACE::i2cAddress'
//There's a whole bunch more after this but not relevant to this question
}
//UBX_COMMS Class Functions
UBLOX_INTERFACE::UBX_COMMS::UBX_COMMS(uint8_t ubxclass, uint8_t id, uint8_t length0, uint8_t length1) : classByte(ubxclass), idByte(id), payloadLength{length0, length1}, stdPacketLength(packetLengthCalc(length0, length1)){};
uint8_t UBLOX_INTERFACE::UBX_COMMS::prepAndSendPacket(uint8_t packet[], const uint16_t packetLength)
{
calcAndInsertUBXChecksum(packet, packetLength);
Wire.beginTransmission(i2cAddress); //error: invalid use of non-static data member 'UBLOX_INTERFACE::i2cAddress'
Wire.write(packet, packetLength);
uint8_t errorCode = Wire.endTransmission();
return errorCode;
}
// UBX_CFG_RATE Class Functions
//definition of UBLOX_INTERFACE::UBX_CFG_PRT::setPort() and UBLOX_INTERFACE::UBX_CFG_PRT::poll()
// UBX_CFG_RST Class Functions
//definition of UBLOX_INTERFACE::UBX_CFG_RST::gnssReset() and UBLOX_INTERFACE::UBX_CFG_PRT::hardwareReset()
Example of how I want to use this
void main()
{
UBLOX_INTERFACE u;
u.ubxCFG_RST.hardwareReset();
u.ubxCFG_RATE.set(SOME SETTINGS HERE);
while(true)
{
u.nmea.intakeNMEA();
}
}
The real code I'm working with does not compile. Currently I'm getting errors in all of the subclasses where I attempt to use the UBLOX_INTERFACE::i2cAddress function: error: invalid use of non-static data member 'UBLOX_INTERFACE::i2cAddress' If I change the i2cAddress to be static, then I get a different error saying I have to use a non-static variable in the class construction. And on top of that, I'm unsure if my method of initializing the subclasses within the parent class constructor is even valid. Can anyone explain if this method is valid or what I should be doing instead?
You are trying to access i2cAddress from the class NMEA but you have defined the variable in the class UBLOX_INTERFACE.
The classes might be defined inside each other, but the instances of the classes does not have access to eachothers variable.
Alternatives would be to either make i2cAddress static, or global or to send a pointer or copy of i2cAddress or to UBLOX_INTERFACE to the class NMEA at some point.
Or depending on your code (i do understand it fully), you might want to put i2cAddress as a member variable of NMEA, that would also solve the problem.
Edit:
If you want to initialize a static member variable in the constructor, it is not possible to do it in the initializer list
//UBLOX_INTERFACE Class Functions
UBLOX_INTERFACE::UBLOX_INTERFACE(uint8_t address) // not here :
{
i2cAddress = address; // This should work
// The following variables does only exist in this function,
// I think that you might want to move these to the function body
// instead
NMEA nmea;
UBX_CFG_RATE ubxCFG_RATE(0x06, 0x08, 0, 6); //These values are permanently defined constants for each command type
UBX_CFG_RST ubxCFG_RST(0x06, 0x04, 0, 4);
}
And about if it would be possible to initialize like classes like you do: No I dont think it works like it does now. You need to add the classes as class members, and then initialize them in the initialize list like you previously did with i2cAddress.

Accessing union elements in C++

I have been implementing a communication protocol in C++ and I have decided to model one packet in below given manner.
union control_pkt_u{
struct pkt_parts_t{
uint8_t header[3]; // Control packet header
uint8_t payload[NO_PYLD_BYTES_IN_CONTROL_PACKET]; // Control packet payload
};
uint8_t pkt_array[NO_BYTES_IN_PACKET];
};
As soon as I need to access to the elements of the union
pkt.pkt_parts_t.header[0] = APP_MSG_DEB;
I receive an error during compilation:
invalid use of struct Manager::control_pkt_u::pkt_parts_t
Please can anybody tell me what I am doing wrong?
Because you are just defining a struct in your control_pkt_u union and it is just a declaration, it is not initialised when you create an object from it. You need to declare it as a member like this and reach your member pkt_parts_.
union control_pkt_u {
struct pkt_parts_t {
uint8_t header[3]; // Control packet header
uint8_t payload[NO_PYLD_BYTES_IN_CONTROL_PACKET]; // Control packet payload
} pkt_parts_;
uint8_t pkt_array[NO_BYTES_IN_PACKET];
};
pkt.pkt_parts_.header[0] = APP_MSG_DEB;
You can change the struct definiation to this by using Anonymous structure:
struct {
uint8_t header[3]; // Control packet header
uint8_t payload[NO_PYLD_BYTES_IN_CONTROL_PACKET]; // Control packet payload
} pkt_parts_t;
Then you don't need to change other code.

Packet wrangling from C to C++ or... how Neither Variant nor Any is a Union

The problem in a nutshell: I'm considering a rewrite of some packet handling code for a UDP protocol ... from C to C++. Obviously, I can just use the structures that I had with C to model the data, but then what would be the point? So, for the sake of argument, we have:
struct { uint8:2 type; uint8:6 con_id; uint16 seq_num } packet_header;
struct { packet_header ph; uint16 command; } control_packet;
struct { packet_header ph; uchar8 data[DATASIZE]; } data_packet;
In this case, "type" is 0 for data, 1 for control, 2 for encrypted data and 3 for encrypted control. There would also be structs reprenting each of the control packets, for argument, lets say "open" and "close".
Now... I would normally have a type that the function that fetches the packet returns and the function that sends accepts:
struct {
size_t pkt_len;
union {
uchar8 raw_packet[DATASIZE];
packet_header ph;
control_packet cp;
control_open_packet cop;
control_close_packet ccp;
data_packet dp;
} p;
} packet;
... this is all simplified for argument... but the point is: when sending a packet, we want to create a packet of a certain type and send a generic packet. Conversely, when receiving a packet, you want to receive a generic packet and and cast it to more specific types as you classify it.
So where's the question? My question is: if Variant and Any are not appropriate ways to express this, what are? Am I stuck with union in this case? Certainly I don't violate the stipulation of POD types (so far) for the union. I've been scouring both C++11 and Boost (and to some extent looking at C++14 ... although I'm stuck with C++11) and I don't see offered solutions.
You can use both union as it is in your example or class hierarchy with packet_header a the top and specific derived classes for each type of the packet:
struct packet_header { uint8:2 type; uint8:6 con_id; uint16 seq_num };
struct control_packet : packet_header { uint16 command; };
struct data_packet: packet_header { uchar8 data[DATASIZE]; };
struct packet
{
size_t pkt_len;
union
{
uchar8 raw_packet[DATASIZE];
packet_header ph;
control_packet cp;
control_open_packet cop;
control_close_packet ccp;
data_packet dp;
};
};
Maybe you need to seek for elegance and flexibility in the code that handles your packets. I doubt that defining data in some other way (using boost or using C++17 features) will lead to a considerable gain.
Note the anonymous union in the struct packet. It allows accessing fields of specific packet types directly. C++ style expects the name of the struct directly after the struct keyword.

storing struct variable from function to local struct variable

typenid is a struct that is defined in a class Queue, queue.h
struct typenid{
typenid() : src_type(0), src_id(0){}
uint32_t src_type;
uint32_t src_id;
} node_details;
The following is a type of class in my event driven simulator.
class FindNextHopEvent : public event {
public:
FindNextHopEvent(double time, Packet *packet, Queue::typenid node_details );
~FindNextHopEvent();
void process_event();
Packet *packet;
Queue::typenid local_node_details; // should get the value of node_details
};
I want to use the node_details struct inside process_event() but I don't want to pass it as a parameter (due to various reason). Is there a way for local_node_details (a struct similar to node_details) to capture the value of node_details,so that I can access it in process_event() ? If so how can i do it. If I declare local_node_details as a pointer then I can use "this" operator but for structs how can I do it.
This is how my current definition looks like.
FindNextHopEvent::FindNextHopEvent(
double time,
Packet *packet,
Queue::typenid node_details
): event(NEXT_HOP_EVENT, time) {
this->packet = packet;
Queue::typenid local_node_details= node_details;
}
Any help is much appreciated.
There is a way, by using references. Pass a reference to the structure to the FindNextHopEvent constructor instead, and make your local_node_details structure be a reference, then you can do it:
class FindNextHopEvent : public event {
Queue::typenid& local_node_details;
// ^
// |
// Note use of ampersand to make it a reference
...
};
...
// Note use of ampersand to make it a reference
// |
// v
FindNextHopEvent(double time, Packet *packet, Queue::typenid& node_details )
// Use constructor initializer list to initialize references
: ..., local_node_details(node_details)
{ ... }

converting struct to general message format to be passed to UDP

I have a C++ struct for an update packet to be exchanged between servers, and another struct to implement information about neighbors, and a vector of struct neighbor is inside update packet.
struct neighbor;
struct update_packet {
uint16_t num_update_fields;
uint16_t port;
uint32_t IP;
vector<struct neighbor> neighbors;
update_packet(char * IPstr, int port) :
num_update_fields(num_nodes),
IP(IP_to_int(IPstr)), port((uint16_t) port)
{ };
};
struct neighbor {
uint32_t IP;
uint16_t port;
int16_t nil;
uint16_t server_id;
uint16_t cost;
neighbor(char * IPstr, uint16_t port, uint16_t server_id, uint16_t cost) :
IP(IP_to_int(IPstr)), port(port), nil(0),
server_id(server_id), cost(cost) { };
};
I want to exchange this struct in general message format (like IP datagram, for example) through UDP sockets and read the information in the message on the receiving end.
How can I achieve this? Is my design for the structs a poor design for my purpose?
What you're asking about is serialization. At it's simplest, if you have a POD type and know that the machines at both ends are the same type you can just cast and send:
struct Foo {
uint32_t a;
uint16_t p;
};
Foo f { 1, 2 };
sendto(targetFD, reinterpret_cast<const char*>(&f), sizeof(f), 0);
Your structure couldn't be used this way because of the vector. The data in a vector is dynamically allocated so it isn't laid out with the rest of the structure. If you need a variable length field like this, an array (or a std::array) along with an indicator of the number of elements would be useful.
Casting structures like this is fast but not really portable. If you want to be able to pass to other languages or platforms you would prefer a serialization format. Google's Protocol Buffers (https://code.google.com/p/protobuf/) and several other serialization libraries are designed to allow this.
Slightly more c++ style serialization and deserialization is desribed in this article - https://rodgert.github.io/2014/09/09/type-driven-wire-protocols-with-boost-fusion-pt1/