I'm working on a quite complex and large sketch for my ESP32 and I'm dividing it into threads and classes, splitting everything in different files. For sake of simplicity I'm gonna show you just the idea of my project setup.
For instance, I'm using a BME280 sensor to read temperature, humidity, and pressure values. Therefore, I created an header file called bme280.h and an associated cpp file called bme280.cpp. Here's the content of the two files.
bme280.h
#ifndef BME280_H
#define BME280_H
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#define SEALEVELPRESSURE_HPA (1013.25)
typedef struct {
float temperature;
float pressure;
float humidity;
}bmeData;
class BME280_sensor {
public:
BME280_sensor();
bmeData readBmeData();
private:
Adafruit_BME280 bme;
};
#endif
bme280.cpp
#include "bme280.h"
BME280_sensor::BME280_sensor() {
bool status;
status = bme.begin(0x76);
if (!status) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1);
}
Serial.println("BME280 sensor correctly initialized!");
}
bmeData BME280_sensor::readBmeData() {
bmeData bmeValues;
bmeValues.temperature = bme.readTemperature();
bmeValues.pressure = bme.readPressure() / 100.0F;
bmeValues.humidity = bme.readHumidity();
return bmeValues;
}
This is basically how I'm using every sensor.
Now, my .ino file is busy doing some other job, so I used the pthread library for creating a different thread in charge of reading sensors values. Hence, my .ino file, before doing its job, starts this thread, which I named mainThread. Here's an example:
file.ino
#include <pthread.h>
#include "main.h"
void setup() {
delay(1000);
Serial.begin(115200);
Serial.println("Serial initialized");
pthread_t mainThreadRef;
int mainValue;
mainValue = pthread_create(&mainThreadRef, NULL, mainThread, (void*)NULL);
if (mainValue) {
Serial.println("Main thread error occured");
}
}
void loop() {
// Some other job
}
The main thread, instead, is implemented using a main.h file and a main.cpp file. Here's an example:
main.h
#ifndef MAIN_H
#define MAIN_H
#include <Arduino.h>
void *mainThread();
#endif
main.cpp
#include "main.h"
#include "bme280.h"
void *mainThread() {
BME280_sensor bme;
while (1) {
bmeData bmeValues = bme.readBmeData();
Serial.println(bmeValues.temperature);
Serial.println(bmeValues.humidity);
Serial.println(bmeValues.pressure);
delay(3000);
}
}
Now, I wonder if this whole structure of the project is good, because I'm facing weird values reading, like temperature over 100 or pressure under 0, and some other weird stuff. To be more precise:
Is it "safe" to have a thread acting as the main thread doing all the jobs?
Is it good to have a different class for each sensor that I am using or does it interfere with sensor readings?
Thank you all in advance for you help!
Is it "safe" to have a thread acting as the main thread doing all the jobs?
Yes. The thing where setup() and loop() functions get executed is also a thread. It's probably the first thread in the system, but otherwise there's no difference between it and the threads that you yourself create.
The hard part is not running an isolated process in its own thread - that's usually easy, and often a good idea. The hard part is getting data across different threads. I recommend Mastering the FreeRTOS Real Time Kernel for reading on how FreeRTOS threads (that's what the ESP32 is really using, pthreads is just a wrapper around it) work and how to communicate between them.
Is it good to have a different class for each sensor that I am using or does it interfere with sensor readings?
If you have one class per type of sensor which wraps the mundane details of how to talk to that sensor, then this is generally considered good design (encapsulation etc). But it depends, really. The devil is in the details. Note that the Arduino or Adafruit sensor libraries already do that anyway - they tend to provide a nice, simple interface that you can use without knowing the details of how it works. Don't bother wrapping those (unless you have a clear purpose).
Related
I'm not an expert with C++ since I come from an electronics background.
I'm trying to make a Arduino program that allows anyone to add a sensors easily to a Arduino device using a standard format.
I thought of making a HAL for each sensor, for that I have created a class named Sensor which is the base class for each sensor. The user has to create a subclass that inherits from the Sensor class. This subclass for example is called Sensor_2 (2 is the ID) and it implements functions like:
uint16_t getID( void );
uint8_t getAvailableChannels( void );
void sampleChannel( uint8_t aChannel, uint8_t *aDataSize, uint8_t aDataBuffer[] );
This class is the one that calls its own sensor library which is dependent of the sensor.
Doing it this way I can sample every sensor in an standard way without having to rewrite each sensor library.
I don't know if that is the way to do it but I can't think of anything better.
I have tried to implement that with the following code:
Sensor.h
#ifndef SENSOR_H
#define SENSOR_H
#include "Arduino.h"
class Sensor
{
public:
Sensor();
virtual uint16_t getID( void );
virtual uint8_t getAvailableChannels( void );
virtual void sampleChannel( uint8_t channel, uint8_t dataSize, uint8_t dataBuffer[]);
};
#endif
Sensor_2.h
#ifndef Sensor_2_H
#define Sensor_2_H
#include "Arduino.h"
#include "../../Sensor.h"
#define ID 2
#define CHANNELS 1
class Sensor_2: public Sensor
{
public:
Sensor_2 ( void );
virtual uint16_t getID( void );
virtual uint8_t getAvailableChannels( void );
virtual void sampleChannel( uint8_t aChannel, uint8_t *aDataSize, uint8_t aDataBuffer[] );
};
#endif
Sensor_2.cpp
#include "Sensor_2.h"
Sensor_2::Sensor_2( void )
{
}
uint16_t Sensor_2::getID( void )
{
return (ID);
}
uint8_t Sensor_2::getAvailableChannels( void )
{
return (CHANNELS);
}
void sampleChannel( uint8_t aChannel, uint8_t *aDataSize, uint8_t aDataBuffer[] )
{
aDataSize = 1;
aDataBuffer[0] = hallRead();
}
main.cpp
#include <Logger.h>
#include "ComHandler.h"
#include "./Sensors/Sensor_2/Sensor_2.h"
ComHandler comHandler;
SensorManager* sensorManager = SensorManager::getInstance();
void setup()
{
Serial.begin(115200);
Logger::setLogLevel(Logger::WARNING);
Sensor_2 sensorHall = new Sensor_2;
sensorManager->addSensor(sensorHall);
}
void loop()
{
uint8_t* datasize;
uint16_t buffer[4];
comHandler.checkForData();
sensorManager.getAvailableSensors()[0].sampleChannel(0,dataSize, buffer);
}
The problem is that when trying to compile I get this error:
conversion from 'Sensor_2*' to non-scalar type 'Sensor_2' requested
Sensor_2 sensorHall = new Sensor_2;
^
If instead of:
Sensor_2 sensorHall = new Sensor_2;
I use:
Sensor_2 sensorHall;
I get:
sketch/Sensor.cpp.o:(.literal._ZN6SensorC2Ev+0x0): undefined reference to `vtable for Sensor'
sketch/Winja.ino.cpp.o:(.literal._Z5setupv+0x10): undefined reference to `Sensor_2::Sensor_2()'
sketch/Winja.ino.cpp.o: In function `setup()':
Do you think this is a good way to implement a solution to my problem? If so, how could I fix my error?
If I understood the problem, here you have two issues (one is blocking, the other not).
As for the simplest problem, Sensor_2 sensorHall = new Sensor_2; is not valid, since the new keyword generates a pointer to the object. You have two ways to generate an object and to pass it to the sensor manager (I assume the sensor manager accepts pointer to sensors):
// Solution 1
Sensor_2 *sensorHall = new Sensor_2;
sensorManager->addSensor(sensorHall);
// Solution 2
Sensor_2 sensorHall;
sensorManager->addSensor(&sensorHall);
Please note, however, that if you use solution 2 you must put the sensor definition outside the function. If, for instance, you write
void setup() {
Sensor_2 sensorHall;
sensorManager->addSensor(&sensorHall);
}
then the sensor object will be destroyed after you exit the setup. In order to avoid this, write
Sensor_2 sensorHall;
void setup() {
sensorManager->addSensor(&sensorHall);
}
As for the main problem, I think that arduino does not compile source files outside the main sketch folder (and it does not recursively, so subfolders are not scanned).
However, what you are trying to do is usually done by implementing libraries. You can find different libraries and resources to understand how a library work (for instance, there is a library tutorial on the arduino website). You will have to create a folder inside the library folder, then put inside the source files (in this case you can use subfolders); the compilation will be successful. This way you won't need to copy these files in future projects: they will already be there.
If you don't want to make them shared, and still want to put them in a separate folder, IIRC you can make a special folder called src and put the source files there (again, not in subfolders). The src folder gets merged with the sketch folder when compiling.
My suggestion: make it a library. Fully reusable, easy to maintain, even a bit of highlighting...
I want to call a user space program from a kernel module periodically.But the kernel program is freezing the system, while I try to load it.
following is the program,
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
#include <linux/jiffies.h>
#include <linux/time.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/hrtimer.h>
#include <linux/sched.h>
#include <linux/delay.h>
#define TIME_PERIOD 50000
static struct hrtimer hr_timer;
static ktime_t ktime_period_ns;
static enum hrtimer_restart timer_callback(struct hrtimer *timer){
char userprog[] = "test.sh";
char *argv[] = {userprog, "2", NULL };
char *envp[] = {"HOME=/", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
printk("\n Timer is running");
hrtimer_forward_now(&hr_timer, ktime_period_ns);
printk("callmodule: %s\n", userprog);
call_usermodehelper(userprog, argv, envp, UMH_WAIT_PROC);
return HRTIMER_RESTART;
}
static int __init timer_init() {
ktime_period_ns= ktime_set( 0, TIME_PERIOD);
hrtimer_init ( &hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL );
hr_timer.function = timer_callback;
hrtimer_start( &hr_timer, ktime_period_ns, HRTIMER_MODE_REL );
return 0;
}
static int __exit timer_exit(){
int cancelled = hrtimer_cancel(&hr_timer);
if (cancelled)
printk(KERN_ERR "Timer is still running\n");
else
printk(KERN_ERR "Timer is cancelled\n");
}
module_init(timer_init);
module_exit(timer_exit);
MODULE_LICENSE("GPL");
test.sh is a script which just echoes a comment.
I have tested the call_usermodehelper part and timer part individually and it is working fine. But while I am combining the two codes, the system hangs.
Can anybody please help me to solve the problem.
Quick look around strongly suggests that hrtimer callbacks are executed from an irq context, which is expected - how else are you going to get high resoluton?
But this also means you must no block, while your callback can block due to call_usermodehelper regardless of NOWAIT passed.
So it seems you are testing your module on a kernel with debugging disabled, which is fundamentally wrong.
But this is less relevant as the thing you are trying to achieve in the first place looks fundamentally wrong.
I can only recommend you elaborate what is the actual problem. There is absolutely now way that forking + execing has anything to do with something requiring a high resolution timer.
I want to make a class in cpp for arduino uno that writes on a display. I'm using the LiquidCrystal_I2C library but I can't use it in my class. I know how to do it without a class, but right now I want to build a class and I cant get it to work.
My .h file:
// WriteDisplay.h
#ifndef _WRITEDISPLAY_h
#define _WRITEDISPLAY_h
#if defined(ARDUINO) && ARDUINO >= 100
#include "arduino.h"
#else
#include "WProgram.h"
#endif
#include <Wire/Wire.h>
#include <LiquidCrystal_I2C2004V1/LiquidCrystal_I2C.h>
class WriteDisplayClass
{
public:
WriteDisplayClass();
void write(String text);
private:
LiquidCrystal_I2C lcd(0x27,20,4);
};
extern WriteDisplayClass WriteDisplay;
#endif
My .cpp:
#include "WriteDisplay.h"
WriteDisplayClass::WriteDisplayClass()
{
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
}
WriteDisplayClass::write(String text)
{
lcd.clear();
lcd.print(text);
}
WriteDisplayClass WriteDisplay;
My .ino:
#include "WriteDisplay.h"
WriteDisplayClass wdc;
void setup()
{
wdc.write("Hello World");
}
void loop()
{
}
I'm using AtmelStudio with Visual Micro. I'm getting it to work when I'm only using my .ino-file, but I can't do the same thing in cpp. I'm getting errors that LiquidCrystal_I2C.h can't be found and stuff like that. How should I do to get it to work the way I want it to? Or is it even possible?
Thanks for answer.
Sorry I misread the question the first time.
To use libraries in the .cpp file of an Arduino sketch you must also include them in the master .ino file. They are only compiled if found in the .ino
You can add the includes manually or use the "Project>Add/Import Sketch Library" menu item which will add them to the .ino for you.
Based on this post here the problem with your code is related the class being instantiated as global. The problem comes that the compiler doesn't guarantee the order of global variables processing, so in order to guarantee that the object concerning the display is executed lastly after all the library ones, you have to instantiate it in the setup() function!
The solution to your .ino code is to set a global pointer and then you assign the object inside the setup() function, like so:
#include "WriteDisplay.h"
WriteDisplayClass *wdc;
void setup()
{
wdc = new WriteDisplayClass();
wdc->write("Hello World");
}
void loop()
{
}
I'm trying to creating a logging class where the call to write a log is static. Now, due to performance requirements I'm want to perform the actual logging in a separate thread. Since the function to write to a log is static, I think the thread also needs to be static, which is also tied to another static member function that performs the actual writing of the log. I tried coding it but somehow it hangs during the initialization of the static thread. The code sample that duplicates the behavior is below:
"Logger.h"
#ifndef LOGGER_H
#define LOGGER_H
#include <condition_variable>
#include <mutex>
#include <queue>
#include <string>
#include <thread>
#include <vector>
#define LIBRARY_EXPORTS
#ifdef LIBRARY_EXPORTS // inside DLL
#define LIBRARY_API __declspec(dllexport)
#else // outside DLL
#define LIBRARY_API __declspec(dllimport)
#endif
using namespace std;
namespace Company { namespace Logging {
class LIBRARY_API Logger
{
public:
~Logger();
void static Write(string message, vector<string> categories = vector<string>());
private:
Logger();
Logger(Logger const&) {}
void operator=(Logger const&) {}
static thread processLogEntriesThread;
static void ProcessLogEntries();
};
}}
#endif
"Logger.cpp"
#include "Logger.h"
#include <iostream>
using namespace std;
namespace Company { namespace Logging {
thread Logger::processLogEntriesThread = thread(&Logger::ProcessLogEntries);
Logger::Logger()
{
}
Logger::~Logger()
{
Logger::processLogEntriesThread.join();
}
void Logger::Write(string message, vector<string> categories)
{
cout << message << endl;
}
void Logger::ProcessLogEntries()
{
}
}}
One odd behavior that I found is that the hanging part only happens when the class packaged in a DLL. If I use the class files directly into the console EXE project it seems to be working.
So basically my problem is the hanging part and if I'm doing things correctly.
Thanks in advance...
you can use my logger library => https://github.com/PraGitHub/Prapository/tree/master/C_Cpp/Logger
If this post is found irrelevant, please pardon me.
the hanging part only happens when the class packaged in a DLL
See Dynamic-Link Library Best Practices for full details why it hangs:
You should never perform the following tasks from within DllMain:
Call CreateThread. Creating a thread can work if you do not synchronize with other threads, but it is risky.
The solution is provide an initialization function/object for your logger library that the user must call explicitly in main, rather than having a global thread object initialized before main is entered. This function should create the thread.
Or create the thread on the first logging call using std::call_once. However, this involves an extra conditional check on each logging call. This check may be cheap but it is not free.
I can not see any usage of the logger thread. Having a thread as member in a class did not mean that all member functions will run in the created thread. The destructor of logger will never called, while you have no logger instance. iostream is not thread safe!
What you have to do:
Create some kind of storage to collect the logging infos. This instance must be thread safe!
Push messages from the outside world into this instance. The instance itself must have a own thread which reads from the storage and put the data to the output. This must be done also in a thread safe manner because reading and writing comes from different threads!
NOTE: THE CODE PROVIDED JUST GIVES THE IDEA OF THE STRUCTURE OF THE APPLICATION
I have a Qt application, interfacing with external hardware. The structure is such that the class for interfacing with the hardware inherits from QObject and is composed with the main GUI thread class. Let's say the class is test.h, here is its sample code:
#ifndef TEST_H
#define TEST_H
#include <QLineEdit>
#include <QString>
#include <QTimer>
#include "ui_test.h"
#define TIMEOUT 100
class TestObj;
class TestApp:public QWidget, public Ui::mTestForm
{
Q_OBJECT
public:
TestApp(QWidget* parent=0);
QTimer* mTimer;
bool mWindowClosed;
TestObj* mObj;
public slots:
void UpdateText();
void Exit();
};
class TestObj:public QObject
{
Q_OBJECT
public:
TestObj();
void RandomTest();
};
#endif
Code for test.cpp is
#include "test.h"
TestApp::TestApp(QWidget* parent):QWidget(parent)
{
setupUi(this);
mObj = new TestObj();
mWindowClosed=false;
mLineEdit->setText("Hello");
mTimer=new QTimer();
mTimer->singleShot(1000,this,SLOT(UpdateText()));
connect(mExitButton,SIGNAL(clicked()),this, SLOT(Exit()));
}
void TestApp::UpdateText()
{
if(mWindowClosed)
{
//QApplication::processEvents();
return;
}
else
{
//QApplication::processEvents();
mObj->RandomTest();
mLineEdit->setText("Hi");
mTimer->singleShot(100,this,SLOT(UpdateText()));
}
}
void TestApp::Exit()
{
mWindowClosed=true;
}
Now consider that TestObj class is the one used to interface with the hardware. This class sends three possible commands (in actual code, the above is just a sample structure) with different timeouts to the hardware, thus we have a timer which is used when sending commands (implemented as functions) to the hardware. Each of these has a processEvents entry to identify any changes to variables in the meanwhile.
The problem is this module is responsible for a steady rise in memory during program execution.
When I comment out the UpdateText() function in the TestApp constructor, the app works fine.
My guess is that most likely there is queuing of signal slots due to which the memory increase, because there are lots of GUI events taking place. And since the class isn't implemented as a separate thread and clubbed with the main GUI thread. There is continuous update of the main thread.
Can someone suggest a way out? I don't have the authority to change the design otherwise I would have implemented the interface class as a thread. So if a solution can be suggested with the current design as is, it would be beneficial.
Creating a regular timer, setting its interval to 100 and connecting its timout signal to the
UpdateText function will avoid events piling up.
P.S: You don't need a QTimer object for singleShot, you can call QTimer::singleShot directly.
Wild guess:
Try changing this:
mTimer->singleShot(100,this,SLOT(UpdateText()));
to this:
if (!slotSet)
{
mTimer->singleShot(100,this,SLOT(UpdateText()));
slotSet = true;
}