sleep in function but not block other functions and code - c++

I am on esp8266 module/microcontroller. I have never wrote in C++. Now I am trying to insert my own small "non blocking" function in one file file. My function should wait 5 seconds on background and then print something. But I don't want to delay whole initialization of meInit() for 5 seconds, it should be let's say parallel "non blocking" function. How is this possible please?
void meInit()
{
if (total > 20) total = 20;
value = EEPROM.read(1);
Serial.begin(115200);
Serial.setTimeout(10);
loadSettings(true);
buildMe();
initFirst();
//here I need to call "non-blocking" function with no delay and process immediatelly further
call5sFunct();
...do other functions here immediatelly without 5s delay...
}
void call5sFunct()
{
Sleep(5000);
DEBUG_PRINTLN("I am back again");
}
P.S. short sample is highly appreciated :) thx

Use std::thread to launch call5sFunct(); in other thread, like this:
//...
initFirst();
//here I need to call "non-blocking" function with no delay and process immediatelly further
std::thread t1(call5sFunct);
t1.detach();
...do other functions here immediatelly without 5s delay...
//...
You need to include #include <thread>

You must not sleep at all, but just call your function after 5 seconds have passed, in the loop function. Something like this (untested):
unsigned long start_time = 0;
bool call5sFunct_executed = false;
void meInit()
{
if (total > 20) total = 20;
value = EEPROM.read(1);
Serial.begin(115200);
Serial.setTimeout(10);
loadSettings(true);
buildMe();
initFirst();
// You cannot call it here, but in loop()
// call5sFunct();
// ...do other functions here immediatelly without 5s delay...
}
void call5sFunct()
{
DEBUG_PRINTLN("I am back again");
}
void loop()
{
unsigned long loop_time = millis();
if (!call5sFunct_executed && (loop_time - start_time >= 5000))
{
call5sFunct();
call5sFunct_executed = true;
}
// .... the rest of your loop function ...
}
However, this template must be used extensively programming microcontrollers. It would be really coumbersome and error-prone to write production code like this - but it's important you get the point.
There are many libraries that make it easy to implement asynchronous operations on arduino, hiding this mechanism. For example take a look to TaskScheduler.
Google for "arduino asynchronous functions" and you will find a lot of alternatives.

Related

Using a ThreadPool inside a loop

I have a service that runs without stopping.
While the software runs I call some GET and POST functions that I don't need to wait a response. Speed is important
Today I am doing like bellow, an simple example:
boost::asio::thread_pool ThreadPool(16);
int main(){
while (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0){
string Event = "test";
boost::asio::post(ThreadPool, [=]() {
sendPOSTEvent(Event);
}
}
ThreadPool.stop();
ThreadPool.join();
}
Is that correct? Or can I have problems? Do I need to clean something inside the loop?

QT: Run a function as long as button is toggled

I want to implement a GUI that receives messages from an external device. The "advancedReceiveExample" is waiting for messages. Once it has received one, it does stuff with it, saves it and terminates.
I want to make my function wait for new messages after receiving one as long as the button is toggled.
I have tried this so far:
void MainWindow::on_pushButton_clicked()
{
if (ui.pushButton->isChecked()) {
ui.pushButton->setText("Stop Receiving");
ui.label_3->setText("Receiving...");
advancedReceiveExample(ui.comboBox->currentIndex() + 1);
}
else
{
ui.pushButton->setText("Start Receiving");
ui.label_3->setText("Not Receiving");
}
}
This works perfectly fine but as mentioned above it only receives one message. If I do that:
void MainWindow::on_pushButton_clicked()
{
if (ui.pushButton->isChecked()) {
ui.pushButton->setText("Stop Receiving");
ui.label_3->setText("Receiving...");
while (1)
{
advancedReceiveExample(ui.comboBox->currentIndex() + 1);
}
}
else
{
ui.pushButton->setText("Start Receiving");
ui.label_3->setText("Not Receiving");
}
}
it blocks the function because the state of the button can only be change after the function "on_pushButton_clicked()" has terminated.
Visual Studio 2019
C/C++
EDIT: Okay, I have understood the problem of blocking the thread. Multithreading might be the right option but I am very unexperienced regarding this topic. The <QThread> could be possible. How would you use it?
Do you have suggestions which other library could be used?
Note QT is event-based. If you keep your computer busy inside some function without returning to the main loop frequently, your GUI will freeze.
What you need to do is slice your action that you want to do into small bits that can repeatedly return to the main loop in order to keep the GUI responsive. (Another method yould be to swap out your action into a separate thread and handle it in parallel, killing the thread when the button is released)
Probably the simplest method to do what you want is with timers that you arm in the PushButton::clicked slot, and then check in the timer event whether the button is still pressed, and, if yes, do a bit of your action, save state and re-arm the timer to have you return.
Something along the lines of the following pseudo code should work and execute what you want to do in slices every 10ms:
MainWindow::onPushButtonClicked () {
// do the action, or, alternatively, start a
// parallel thread that does it
do_a_bit_of_action();
// sets up a timer to call onTimer after 10ms
QTimer::singleShot (10, this, SLOT(onTimer()));
}
MainWindow::onTimer () {
// check if button is still held down
if (pushButton.down) {
// re-arm timer
Timer::singleShot (10, this, SLOT(onTimer()));
// do some more action bits
do_a_bit_of_action();
}
else {
// kill optional background thread here
}
}
You can try it with:
while(ui.pushButton->isChecked()){
*your function*
}

detached std::thread on esp32 arduino sometimes blocks, sometimes doesn't

I have some code running on ESP32 microcontroller with arduino core,
In the setup() function I wish to have some code threadPressureCalib run independently in its own thread, so I do the following:
std::unique_ptr<std::thread> sensorCalib;
void setup()
{
sensorCalib.reset(new std::thread(threadPressureCalib));
std::thread* pc = sensorCalib.get();
pc->detach();
}
void loop()
{
...
}
Then, I define threadPressureCalib() as follows:
void threadPressureCalib()
{
float pressure=0;
int count;
for(timestarted = millis();(millis()-timestarted) < 10000;)
{ // THIS ONE BLOCKS SETUP() AND LOOP() CODE EXECUTION
Serial.println("Doing things");
}
Serial.println("Doing other things");
for (count=1; count<= 5;count++)
{ //THIS ONE DOES NOT BLOCK SETUP() and LOOP()
float temp;
while(!timer2.Delay(2000)); //Not sure if this is blocking anything
do{
temp = adc_pressure();
}while(temp>104.0 || temp<70.0); //Catch errors
pressure += temp;
}
changeSetting(pressure/5.0);
return;
}
Problem: During the first for loop, the setup() function's execution is stopped (as well as loop())
During the second for loop, nothing is stopped and the rest of the code runs in parallel (as expected)
Why is it that the first half of this code blocks, and then the second half does not?
Sorry if the question is vague or improperly asked, my first q here.
Explanation of timer2 per request in comments:
timer2 is a custom timer class, timer2.Delay(TIMEOUT) stores timestamp the first time it's called and returns false on every subsequent call until the current time = TIMEOUT, then it returns true and resets itself
NonBlockDelay timer2;
//time delay function (time in seconds to delay)
// Set iTimeout to current millis plus milliseconds to wait for
/**
* Called with milliseconds to delay.
* Return true if timer expired
*
*/
//Borrowed from someone on StackOverflow...
bool NonBlockDelay::Delay (unsigned long t)
{
if(TimingActive)
{
if((millis() >iTimeout)){
TimingActive = 0;
return(1);
}
return(0);
}
iTimeout = millis() + t;
TimingActive = 1;
return(0);
};
// returns true if timer expired
bool NonBlockDelay::Timeout (void)
{
if(TimingActive){
if((millis() >iTimeout)){
TimingActive = 0;
iTimeout = 0;
return(1);
}
}
return(false);
}
// Returns the current timeout value in milliseconds
unsigned long NonBlockDelay::Time(void)
{
return iTimeout;
}
There is not enough information here to tell you the answer but it seems that you have no idea what you are doing.
std::unique_ptr<std::thread> sensorCalib;
void setup(){
sensorCalib.reset(new std::thread(threadPressureCalib));
std::thread* pc = sensorCalib.get();
pc->detach();
}
So here you store a new thread that executes threadPressureCalib then immediately detach it. Once the thread is detached the instance std::thread no longer manages it. So what's the point of even having std::unique_ptr<std::thread> sensorCalib; in the first place if it literally does nothing? Do you realize that normally you need to join the thread if you wish to wait till it's completion? Could it be that you just start a bunch of instances of these threadPressureCalib - as you probably don't verify that they finished execution - and they interfere with each other?

Interrupt arduino routine to run a slow delay based process

I have an arduino that does mostly data collection and sends it to an ESP8266 over serial. Serial communication to the ESP is not quick as you may know and it depends on a lot of waiting. I have a button and I want to immediately stop any data collection or sending and have it open a door. The door opening takes about 30 seconds. What's the best way to do this?
Not the full code, but it goes something like the below.
Of course this doesn't work because you can't use WHILE or DELAY in an ISR, but I don't know how to restructure it.
attachInterrupt(4 , openadoor, FALLING);
void loop(){
gathersomedata();
senddatatoESP();
if(wait_for_esp_response(2000,"OK")) lightGreenLED();
else lightRedLED();
}
byte wait_for_esp_response(int timeout, const char* term) {
unsigned long t = millis();
bool found = false;
int i = 0;
int len = strlen(term);
while (millis() < t + timeout) {
if (Serial2.available()) {
buffer[i++] = Serial2.read();
if (i >= len) {
if (strncmp(buffer + i - len, term, len) == 0) {
found = true;
break;
}
}
}
}
buffer[i] = 0;
}
void openadoor(){
while (doortimer + dooropentime >= millis() && digitalRead(openbutton) == HIGH && digitalRead(closebutton) == HIGH) {
digitalWrite(DoorOpenRelay, LOW);
}
digitalWrite(DoorOpenRelay, HIGH);
}
TL;DR - see Nick's Answer. :-)
Without the complete code, I can only guess at a few things:
1) You shouldn't wait in an ISR. Even calling millis() is discouraged, as it depends on the Timer0 ISR getting called, which will be prevented as long as you're in your openadoor ISR.
2) In general, the ISR should only do things that are very quick... think microseconds. That's tens to hundreds of instructions, which can be just a few lines of code. Even digitalWrite is almost too slow. If there's more to do, you should just set a volatile flag that is watched in loop. Then loop can do the time-consuming work.
3) Calculating elapsed time must be in this form:
if (millis() - startTime >= DESIRED_TIME)
where startTime is the same type as millis(), a uint32_t:
uint32_t startTime;
You set startTime whereever it's appropriate:
startTime = millis();
This avoids the rollover problem, when millis() rolls over from 232-1 to 0.
4) It looks like you know how to "block" until a certain amount of time has elapsed: the while loop will keep your sketch at that point. If you just change it to an if statement, the Arduino can continue on its way to handle other things.
Because loop happens so quickly, the if statement will check the time very frequently... unless you delay or block somewhere else, like wait_for_esp_response. :-( That while loop should change to an if statement as well. The routine is more like check_for_esp_response.
5) You have to track the state of the door opening and closing process. This is a Finite-State machine problem. Nick has a good description here, too. You can use the enum type to define the states that the door can be in: CLOSED, OPENING, OPENED and CLOSING.
When the OPEN button is pressed, you can look at the state and see if you should start opening it. Then start a timer, turn on the relay and, most importantly, set the state to OPENING. Next time through loop, you can test the state (a switch statement), and for the OPENING case, look at the time to see if it has been long enough. If it has set the state to OPENED. And so on.
If I incorporate all these things into your sketch, it should start to look like this:
volatile bool doorOpenPressed = false;
volatile bool doorClosePressed = false;
static const uint32_t DOOR_OPEN_TIME = 30000UL; // ms
static const uint32_t DOOR_CLOSE_TIME = 30000UL; // ms
static const uint32_t DATA_SAMPLE_TIME = 60000UL; // ms
static uint32_t lastDataTime, sentTime, relayChanged;
static bool waitingForResponse = false;
static uint8_t responseLen = 0;
enum doorState_t { DOOR_CLOSED, DOOR_OPENING, DOOR_OPENED, DOOR_CLOSING };
doorState_t doorState = DOOR_CLOSED;
void setup()
{
attachInterrupt(4 , openadoor, FALLING);
}
void loop()
{
// Is it time to take another sample?
if (millis() - lastDataTime > DATA_SAMPLE_TIME) {
lastDataTime = millis();
gathersomedata();
// You may want to read all Serial2 input first, to make
// sure old data doesn't get mixed in with the new response.
senddatatoESP();
sentTime = millis();
waitingForResponse = true;
responseLen = 0; // ready for new response
}
// If we're expecting a response, did we get it?
if (waitingForResponse) {
if (check_for_esp_response("OK")) {
// Got it!
lightGreenLED();
waitingForResponse = false;
} else if (millis() - sentTime > 2000UL) {
// Too long!
lightRedLED();
waitingForResponse = false;
} // else, still waiting
}
// Check and handle the door OPEN and CLOSE buttons,
// based on the current door state and time
switch (doorState) {
case DOOR_CLOSED:
if (doorOpenPressed) {
digitalWrite(DoorOpenRelay, LOW);
relayChanged = millis();
doorState = DOOR_OPENING;
}
break;
case DOOR_OPENING:
// Has the door been opening long enough?
if (millis() - relayChanged > DOOR_OPEN_TIME) {
digitalWrite(DoorOpenRelay, HIGH);
doorState = DOOR_OPENED;
} else if (!doorOpenPressed && doorClosePressed) {
// Oops, changed their mind and pressed the CLOSE button.
// You may want to calculate a relayChanged time that
// is set back from millis() based on how long the
// door has been opening. If it just started opening,
// you probably don't want to drive the relay for the
// full 30 seconds.
...
}
break;
case DOOR_OPENED:
if (doorClosePressed) {
...
}
break;
case DOOR_CLOSING:
if (millis() - relayChanged > DOOR_CLOSE_TIME) {
...
}
break;
}
}
void openadoor()
{
doorOpenPressed = true;
}
bool check_for_esp_response(const char* term)
{
bool found = false;
if (Serial2.available()) {
// You should make sure you're not running off the end
// of "buffer" here!
buffer[responseLen++] = Serial2.read();
int len = strlen(term);
if (responseLen >= len) {
if (strncmp(buffer + responseLen - len, term, len) == 0) {
found = true;
}
}
}
return found;
}
The key is that you don't block or delay anywhere. loop gets called over and over, and it just checks a few variables. Most of the time, there's nothing to do. But sometimes, based on the state or the current time, it gathers some data, sends it, reads the response, and opens or closes the door. These actions do not interfere with each other, because there are no blocking while loops, only quick checks with if statements.
Open the door in the ISR and set a flag. Also store the time when you opened it. Both of those variables should be declared volatile.
Then in your main loop see if:
The flag is set; and
Time is up
If so, close the door (and clear the flag).
May I assume that setting the variables as "volatile" will prevent the compiler optimizing them? If so, then would you mind explaining why you thought this necessary.
Variables modified inside an ISR may change when the compiler does not expect them to. Using volatile tells the compiler to reload such variables from RAM (and not cache them into a register) so it always gets the most up-to-date copy.
Just as an example, say you had a flag set inside an ISR. And in your main (non-ISR) code you had this:
flag = false;
while (!flag)
{ } // wait for flag to be set
The compiler looks at that and thinks "well, flag will never change" and optimizes away the test for it changing. With volatile though, the compiler keeps the test, because it has to keep reloading flag from RAM.

linux c++ how to call function after specific time interval

Let's say I have some function func() in my program, and I need it to be called after some specific delay. So far I have googled it and ended up with folowing code:
#include <stdio.h>
#include <sys/time.h> /* for setitimer */
#include <unistd.h> /* for pause */
#include <signal.h> /* for signal */
void func()
{
printf("func() called\n");
}
bool startTimer(double seconds)
{
itimerval it_val;
double integer, fractional;
integer = (int)seconds;
fractional = seconds - integer;
it_val.it_value.tv_sec = integer;
it_val.it_value.tv_usec = fractional * 1000000;
it_val.it_interval = it_val.it_value;
if (setitimer(ITIMER_REAL, &it_val, NULL) == -1)
return false;
return true;
}
int main()
{
if (signal(SIGALRM, (void(*)(int))func) == SIG_ERR)
{
perror("Unable to catch SIGALRM");
exit(1);
}
startTimer(1.5);
while(1)
pause();
return 0;
}
And it works, but the problem is that settimer() causes func() to be called repeatedly with interval of 1.5 sec. And what I need, is to call func() just once.
Can someone tell me how to do this? Maybe, I need some additional parameters to settimer() ?
Note: time interval should be precise, because this program will play midi music later.
Unless you need the program to be doing other things, you can simply sleep for the time allotted.
If you need to use the alarm, you can install the alarm to be processed once.
From the man page:
struct timeval it_interval
This is the period between successive timer interrupts. If zero, the alarm will only be sent once.
Instead of your code:
it_val.it_interval = it_val.it_value;
I'd set:
it_val.it_interval.tv_sec = 0;
it_val.it_interval.tv_usec = 0;
In addition to it_val.it_value which you already set. What you've done is use the same values for both structures, and that is why you see a repeated interval.