How to add a delay time to start a new reading? - c++

I'm trying to develop a smart lock, with an rfid module, an esp8266 and integration with SinricPro (which makes the bridge for the lock to integrate with Alexa and Google Home)
It turns out that I'm having a very annoying problem, and I would like your help to solve it!
In this function, I execute what needs to be executed after the card passes the RFID module:
void handleRFID() {
if (RFID_card_is_not_present()) return;
String card_id = get_RFID_card_ID();
bool RFID_card_is_valid = validate_RFID_card(card_id);
if (RFID_card_is_valid) {
Serial.printf("The RFID card \"%s\" is valid.\r\n", card_id.c_str());
unlock_with_auto_relock();
send_lock_state(false);
// Insert a timeout here, to start reading the card again only after TEMP_AUTOLOCK is over
} else {
Serial.printf("The RFID card \"%s\" is not valid.\r\n", card_id.c_str());
// Insert a delay time here, to start reading the card again only after X time (something like 3 seconds)
}
}
If I run the code as it is, my serial monitor is spammed with a message that the card is valid/not valid, and it sends a shower of requests to the SinricPro api, as I have nothing limiting the reading of cards in the rfid module for X time, as a delay() function
But unfortunately I can't use delay(), so it's already out of the question
So basically what I want to do is limit the speed at which the cards are read by inserting some wait time where I put the comments in the code. Can someone help me?
For better understanding, I'll make my code available, and the RFID module library I'm using!
Project code: https://github.com/ogabrielborges/smartlock-rfid-iot
MRFC522 library: https://github.com/miguelbalboa/rfid
My serial monitor is spammed with messages that inform that the card is registered/not registered because I don't know how to limit the time that the module reads the tag
printscreen of the serial monitor with the message spam when keeping the tag on the sensor

There is a "blink without delay" example in the arduino environment (or there used to be?).
You can find a similar example here: https://docs.arduino.cc/built-in-examples/digital/BlinkWithoutDelay
Basically what you do is remember the current time in a global and check if enough time has passed for the next check:
These are your globals:
unsigned long previousMillis = 0; // will store last time you did your magic
const long interval = 1000; // interval at which to do your magic (milliseconds, 1000 = 1 sec)
Then do this somewhere in a function:
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// save the last time you did your magic
previousMillis = currentMillis;
// Do your magic here
}

Related

Esp8266 Timer instead of delay

I'm working on a smart Irrigation system built on an ESP8266 microcontroller coded on Arduino ide; basically I want to send data of temperature to my database every 4 minutes, check the sensors every 10 minutes, or execute any code after a certain time , but I don't want to use delay() since other codes in the same loop should keep on executing.
So, is there a way to use another function that can execute the rest code and when the timer is done it executes the sending to database?
Thanks
The Arduino package manager has a library called NTPClient, which provides, as you might guess, an NTP client. Using this with the system clock lets you keep reasonable time without a battery-backed RTC.
Once you know what time it is, scheduling events becomes trivial. This isn't a fully working example, but should give you the idea. The docs have more information. The NTPClient also works quite well with the AceTime library for time zone and other management.
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <ESP8266WiFi.h>
#include <AceTime.h>
#include <ctime>
using namespace ace_time;
using namespace ace_time::clock;
using namespace std;
WiFiUDP ntpUDP;
const long utcOffsetInSeconds = 0;
// Get UTC from NTP - let AceTime figure out the local time
NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds, 3600);
//3600s/h - sync time once per hour, this is sufficient.
// don't hammer pool.ntp.org!
static BasicZoneProcessor estProcessor;
static SystemClockLoop systemClock(nullptr /*reference*/, nullptr /*backup*/);
const char* ssid = // your SSID;
const char* password = // your wifi password;
void setup() {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("Connecting to wifi...");
while (WiFi.status() != WL_CONNECTED) {
Serial.println('.');
delay(500);
}
systemClock.setup();
timeClient.begin();
}
int clockUpdateCounter = 50000;
void loop(){
// Update the system clock from the NTP client periodically
if (++clockUpdateCounter > 50000){ // can be more elegant than this... depends on your loop speed, can actually use the real time for this too, I'm just making this simple because I don't have a lot of time...
clockUpdateCounter = 0;
timeClient.update();
// doesn't matter how often you call timeClient.update().
// you can put this in the main loop() if you want.
// We supplied 3600s as the refresh interval in the constructor
// and internally .update() checks whether enough time has passed
// before making a request to the NTP server itself
auto estTz = TimeZone::forZoneInfo(&zonedb::kZoneAmerica_Toronto, &estProcessor);
auto estTime = ZonedDateTime::forUnixSeconds(timeClient.getEpochTime(), estTz);
// using the system clock is optional, but has a few
// conveniences. Here we just make sure that the systemClock remains
// sync'd with the NTP server. Doesn't matter how often you do this
// but usually around once an hour is plenty
systemClock.setNow(estTime.toEpochSeconds());
}
systemClock.loop();
delay(30);
}
The above keeps the system clock in sync with the NTP server. You can then use the system clock to fetch the time and use it for all types of timing purposes. eg :
// get Time
acetime_t nowT = systemClock.getNow();
auto estTz = TimeZone::forZoneInfo(&zonedb::kZoneAmerica_Toronto, &estProcessor);
auto nowTime = ZonedDateTime::forEpochSeconds(nowT, estTz);
Checking the time is fast, so you can do it inside loop() and only trigger the action when whatever time has elapsed.
This is a particularly nice solution for database integration since you can record a real timestamp of the actual date and time when logging your data to the database.

Wait simulation time Omnet++

I need to modify UdpEchoApp (from Inet package) so that before it sends back the packet it waits "x" seconds of simulation time. I tried doing something like:
simtime_t before;
//something to calculate
simtime_t after;
if (after-before > x) {continue}
else {do something and then recalculate after}
but this crashes Qtenv. Is there something i can do to resolve this problem ?
I also post the function that sends back the received packet:
void UdpEchoApp::socketDataArrived(UdpSocket *socket, Packet *pk)
{
// determine its source address/port
L3Address remoteAddress = pk->getTag<L3AddressInd>()->getSrcAddress();
int srcPort = pk->getTag<L4PortInd>()->getSrcPort();
pk->clearTags();
pk->trim();
// statistics
numEchoed++;
emit(packetSentSignal, pk);
// send back
socket->sendTo(pk, remoteAddress, srcPort);
}
Thank you
Your code is wrong: simulation time is increased by simulation environment according to incoming events. In other words, simulation time is modified outside the standard methods that defines a behavior of a module.
To simulate a delay during the simulation one has to use a selfmessage.
In short:
In socketDataArrived():
remember the packet to send and remoteAddress in a buffer,
schedule a selfmessage x seconds later (using scheduleAt()).
In handleMessageWhenUp() when your selfmessage occurs take the packet from the buffer and send it.

QCustomPlot Huge Amount of Data Plotting

I am trying to plot some serial data on my Qt Gui program using qcustomplot class. I had no trouble when I tried to plot low sampling frequency datas like 100 data/second. The graph was really cool and was plotting the data smoothly. But at high sampling rates such 1000data/second, plotter makes a bottleneck for serial read function. It slow downs serial there was a huge delay like 4-5 seconds apart from device. Straightforwardly, plotter could not reach the data stream speed. So, is there any common issue which i dont know about or any recommendation?
I thougth these scenarious,
1- to devide whole program to 2 or 3 thread. For example, serial part runs in one thread and plotting part runs in another thread and two thread communicates with a QSemaphore
2- fps of qcustom plot is limited. but there should be a solution because NI LABVIEW plots up to 2k of datas without any delay
3- to desing a new virtual serial device in usb protocol. Now, I am using ft232rl serial to usb convertor.
4- to change programming language. What is the situation and class support in C# or java for realtime plotting? (I know it is like a kid saying, but this is a pretex to be experienced in other languages)
My serial device send data funct(it is foo device for experiment there is no serious coding) is briefly that:
void progTask()
{
DelayMsec(1); //my delay function, milisecond
//read value from adc13
Adc13Read(adcValue.ui32Part);
sendData[0] = (char)'a';
sendData[1] = (char)'k';
sendData[2] = adcValue.bytes[0];
sendData[3] = (adcValue.bytes[1] & 15);
Qt Program read function is that:
//send test data
UARTSend(UART6_BASE,&sendData[0],4);
}
union{
unsigned char bytes[2];
unsigned int intPart;
unsigned char *ptr;
}serData;
void MedicalSoftware::serialReadData()
{
if(serial->bytesAvailable()<4)
{
//if the frame size is less than 4 bytes return and
//wait to full serial receive buffer
//note: serial->setReadBufferSize(4)!!!!
return;
}
QByteArray serialInData = serial->readAll();
//my algorithm
if(serialInData[0] == 'a' && serialInData[1] == 'k')
{
serData.bytes[0] = serialInData[2];
serData.bytes[1] = serialInData[3];
}else if(serialInData[2] == 'a' && serialInData[3] == 'k')
{
serData.bytes[0] = serialInData[0];
serData.bytes[1] = serialInData[1];
}
else if(serialInData[1] == 'a' && serialInData[2] == 'k')
{
serial->read(1);
return;
}else if(serialInData[0] == 'k' && serialInData[3] == 'a')
{
serData.bytes[0] = serialInData[1];
serData.bytes[1] = serialInData[2];
}
plotMainGraph(serData.intPart);
serData.intPart = 0;
}
And qcustom plot setting fuction is:
void MedicalSoftware::setGraphsProperties()
{
//MAIN PLOTTER
ui->mainPlotter->addGraph();
ui->mainPlotter->xAxis->setRange(0,2000);
ui->mainPlotter->yAxis->setRange(-0.1,3.5);
ui->mainPlotter->xAxis->setLabel("Time(s)");
ui->mainPlotter->yAxis->setLabel("Magnitude(mV)");
QSharedPointer<QCPAxisTickerTime> timeTicker(new QCPAxisTickerTime());
timeTicker->setTimeFormat("%h:%m:%s");
ui->mainPlotter->xAxis->setTicker(timeTicker);
ui->mainPlotter->axisRect()->setupFullAxesBox();
QPen pen;
pen.setColor(QColor("blue"));
ui->mainPlotter->graph(0)->setPen(pen);
dataTimer = new QTimer;
}
And the last is plot function:
void MedicalSoftware::plotMainGraph(const quint16 serData)
{
static QTime time(QTime::currentTime());
double key = time.elapsed()/1000.0;
static double lastPointKey = 0;
if(key-lastPointKey>0.005)
{
double value0 = serData*(3.3/4096);
ui->mainPlotter->graph(0)->addData(key,value0);
lastPointKey = key;
}
ui->mainPlotter->xAxis->setRange(key+0.25, 2, Qt::AlignRight);
counter++;
ui->mainPlotter->replot();
counter = 0;
}
Quick answer:
Have you tried:
ui->mainPlotter->replot(QCustomPlot::rpQueuedReplot);
according to the documentation it can improves performances when doing a lot of replots.
Longer answer:
My feeling on your code is that you are trying to replot as often as you can to get a "real time" plot. But if you are on a PC with a desktop OS there is no such thing as real time.
What you should care about is:
Ensure that the code that read/write to the serial port is not delayed too much. "Too much" is to be interpreted with respect to the connected hardware. If it gets really time critical (which seems to be your case) you have to optimize your read/write functions and eventually put them alone in a thread. This can go as far as reserving a full hardware CPU core for this thread.
Ensure that the graph plot is refreshed fast enough for the human eyes. You do not need to do a full repaint each time you receive a single data point.
In your case you receive 1000 data/s which make 1 data every ms. That is quite fast because that is beyond the default timer resolution of most desktop OS. That means you are likely to have more than a single point of data when calling your "serialReadData()" and that you could optimize it by calling it less often (e.g call it every 10ms and read 10 data points each time). Then you could call "replot()" every 30ms which would add 30 new data points each time, skip about 29 replot() calls every 30ms compared to your code and give you ~30fps.
1- to devide whole program to 2 or 3 thread. For example, serial part
runs in one thread and plotting part runs in another thread and two
thread communicates with a QSemaphore
Dividing the GUI from the serial part in 2 threads is good because you will prevent a bottleneck in GUI to block the serial communication. Also you could skip using semaphore and simply rely on Qt signal/slot connections (connected in Qt::QueuedConnection mode).
4- to change programming language. What is the situation and class
support in C# or java for realtime plotting? (I know it is like a kid
saying, but this is a pretex to be experienced in other languages)
Changing the programming language, in best case, won't change anything or could hurt your performances, especially if you go toward languages which are not compiled to native CPU instructions.
Changing the plotting library on the other hand could change the performances. You can look at Qt Charts and Qwt. I do not know how they compare to QCustomPlot though.

Android usb host input bulktransfer fails to read randomly when data available

The following code is inside a thread and reads input data coming over usb. Approximately every 80 readings it misses one of the packets coming from an stm32 board. The board is programmed to send data packets to the android tablet every one second.
// Non Working Code
while(running){
int resp = bulktransfer(mInEp,mBuf,mBuf.lenght,1000);
if(resp>0){
dispatchMessage(mBuf);
}else if(resp<0)
showsBufferEmptyMessage();
}
I was looking the Missile Launcher example in android an other libraries on the internet and they put a delay of 50ms between each poll. Doing this it solves the missing package problem.
//Working code
while(running){
int resp = bulktransfer(mInEp,mBuf,mBuf.lenght,1000);
if(resp>0){
dispatchMessage(mBuf);
}else if(resp<0)
showsBufferEmptyMessage();
try{
Thread.sleep(50);
}catch(Exception e){}
}
Does anyone knows the reason why the delay works. Most of the libraries on github has this delay an as I mention before the google example too.
I am putting down my results regarding this problem. After all seems that the UsbConnection.bulkTransfer(...) method has some bug when called continuously. The solution was to use the asynchronous API, UsbRequest class. Using this method I could read from the input endpoint without delay and no data was lost during the whole stress test. So the direction to take is asynchronous UsbRequest instead of synchronously bulktransfer.

running a background process on arduino

I am trying to get my arduino mega to run a function in the background while it is also running a bunch of other functions.
The function that I am trying to run in the background is a function to determine wind speed from an anemometer. The way it processes the data is similar to that of an odometer in that it reads the number of turns that the anemometer makes during a set time period and then takes that number of turns over the time to determine the wind speed. The longer time period that i have it run over the more accurate data i receive as there is more data to average.
The problem that i have is there is a bunch of other data that i am also reading in to the arduino which i would like to be reading in once a second. This one second time interval is too short for me to get accurate wind readings as not enough revolutions are being completed by the anemometer to give high accuracy wind data.
Is there a way to have the wind sensor function run in the background and update a global variable once every 5 seconds or so while the rest of my program is running simultaneously and updating the other data every second.
Here is the code that i have for reading the data from the wind sensor. Every time the wind sensor makes a revolution there is a portion where the signal reads in as 0, otherwise the sensor reads in as a integer larger than 0.
void windmeterturns(){
startime = millis();
endtime = startime + 5000;
windturncounter = 0;
turned = false;
int terminate = startime;
while(terminate <= endtime){
terminate = millis();
windreading = analogRead(windvelocityPin);
if(windreading == 0){
if(turned == true){
windturncounter = windturncounter + 1;
turned = false;
}
}
else if(windreading >= 1){
turned = true;
}
delay(5);
}
}
The rest of the processing of takes place in another function but this is the one that I am currently struggling with. Posting the whole code would not really be reasonable here as it is close to a 1000 lines.
The rest of the functions run with a 1 second delay in the loop but as i have found through trial and error the delay along with the processing of the other functions make it so that the delay is actually longer than a second and it varies based off of what kind of data i am reading in from the other sensors so a 5 loop counter for timing i do not think will work here
Let Interrupts do the work for you.
In short, I recommend using a Timer Interrupt to generate a periodic interrupt that measures the analog reading in the background. Subsequently this can update a static volatile variable.
See my answer here as it is a similar scenario, detailing how to use the timer interrupt. Where you can replace the callback() with your above analogread and increment.
Without seeing how the rest of your code is set up, I would try having windturncounter as a global variable, and add another integer that is iterated every second your main program loops. Then:
// in the main loop
if(iteratorVariable >= 5){
iteratorVariable = 0;
// take your windreading and implement logic here
} else {
iteratorVariable++;
}
I'm not sure how your anemometer stores data or what other challenges you might be facing, so this may not be a 100% solution, but it would allow you to run the logic from your original post every five seconds.