Trying to understand more complex project structure in C . This is for an nrf52840 (embedded 2.4Ghz radio device). But the question is about C but using it for an example.
Say I have 5 files I created:
1) main.cpp
2) mouse.cpp
3) mouse.h
4) radio_controls.cpp
5) radio_controls.h
There is also a .h I included:
1) esb.h
In esb.h there is a function called esb_set_rf_channel(int) which is used to set a frequency on the radio device to receive and transmit on. I included it in radio_controls.h since I use functions defined in esb.h in the radio_controls.h and radio_controls.cpp.
I included radio_controls.h in mouse.cpp since I need to control the radio device for the mouse to mostly transmit move commands.
Is this even proper? What is the recommended standard? I now can call esb_set_channel(int) directly in mouse.cpp but the intent was to have all the radio stuff in radio_controls and maybe have a helper member function call it for me from radio_controls. I also want to avoid including header files too many times where you might start to run into issues since esb.h is not my file as a project gets larger I could see this as an issue.
Edit: Code for more clarity. Main problem is I need a structure from esb.h in radio_controls.h. Maybe I could have a struct of my own for the settings I want to change and have the implantation file create the esb.h struct on the stack? This seems terrible too.
radio_controls.h
#ifndef RADIO_CONTROLS_H
#define RADIO_CONTROLS_H
#include <esb.h>
class RadioControls {
private:
esb_config config; // this structure is from esb.h (this is why I need the #include <esb.h> here
// config changes from default that need to be added by mouse
// and need to set RF
//config.retransmit_delay = 250; // lower retransmit delay from default of 600
//config.event_handler = event_handler; // add radio event handler
int clocks_start(void); // start HF clock (needed for ESB to work)
int esb_initialize(void); // initialize esb radio
// want a structure for esb initialize values to be passed in
// rx and tx payloads
static struct esb_payload rx_payload;
static struct esb_payload tx_payload;
public:
RadioControls(); // initialize radio on nrf device
int esb_set_rf_channel(uint32_t channel); // set rf channel to first element in array of unifying
// could be a helper function like set_rf(uint32 channel); and implementation file calls esb.h defined one
}; // namespace controls::radio
#endif // RADIO_CONTROLS_H
#ifndef MOUSE_H
#define MOUSE_H
/*
* Initialize mouse.
*
* And need to restore any settings from
flash.
*
*/
class mouse {
private:
// restore mouse settings from flash
public:
Mouse(); // create unifying mouse
// ~Mouse(); // reset to default and disable
// int move_mouse(); // x, y mouse move command
// initialize esb radio
// set radio to default settings for mouse
// this includes RF, address for pipes, etc.
};
#endif // MOUSE_H
CodePudding user response:
There's a little rule that helps me make my code a little bit clear. The rule sounds like that:
Do not add include directives in header files
Sometimes it's impossible, and that's OK. In your solution, you can make your radio_controls.h
as clear as possible. Something like that:
#pragma once
namespace controls::radio {
using result_t = unsigned char;
result_t initialize();
result_t set_channel(const unsigned char channel);
} // namespace controls::radio
And your cpp file could be like:
#include "radio_controls.h"
#include <esb.h>
namespace controls::radio {
result_t initialize() {
return esb_init();
}
result_t set_channel(const unsigned char channel) {
return etb_set_rf_channel(channel);
}
} // namespace controls::radio
I didn't use classes in my examples because, as I understand, you're an embedded developer, but I still highly recomend to use classes in a case like that. You could make a class named radio::Controls
or etc.
But, of course, if your compiler allows doing it. Anyway, I hope I answered to your question.
Assuming I can make another rule:
Include additional functionality only in those files, where you really need it. Avoid to add includes into header files
CodePudding user response:
@Steve4879, yes, There's a way to use structures from the esb.h. You can use forward declaration
for it. Take a look:
#pragma once
#include <memory>
class ClassFromLibrary;
struct StructFromLibrary;
namespace controls::radio {
std::shared_ptr<ClassFromLibrary> makeClassFromLib(const StructFromLibrary &data);
// here will be error:
ClassFromLibrary makeClassFromLib(StructFromLibrary data);
// Because the forward declared classes can only be pointers or referencies
} // namespace controls::radio