I am using QT 4.7, and have a timer that will execute a function 2 times a second or 4 times a second based on what type of sound is required.
void Keypad::SoundRequest(bool allowBeeps, int beepType)
{
// Clear any Previous active Timer
if (sound1Timer->isActive() == true)
{
sound1Timer->stop();
}
else if(sound2Timer->isActive() == true)
{
sound2Timer->stop();
}
// Zero out main
(void) memset(&soundmain_t, (char) 0, sizeof(soundmain_t));
// Zero out sound1
(void) memset(&sound1_t, (char) 0, sizeof(sound1_t));
// Zero out the sound2
(void) memset(&sound2_t, (char) 0, sizeof(sound2_t));
if (allowBeeps == true)
{
if(beepType == OSBEEP)
{
sound1Timer->start(500); // 250mS On / 250mS off called every 500mS = 2HZ
}
else if (beepType == DOORBEEP)
{
sound2Timer->start(250); // 125mS On / 125mS off called every 250mS = 4HZ
}
}
else if (allowBeeps == false)
{
//Shut the Beeper Down
if (sound1Timer->isActive() == true)
{
sound1Timer->stop();
}
else if(sound2Timer->isActive() == true)
{
sound2Timer->stop();
}
SOUND_BLAST(0, &soundmain_t);
}
}
Constructor:
sound1Timer = new QTimer(this);
sound2Timer = new QTimer(this);
connect(sound1Timer, SIGNAL(timeout()), this, SLOT(sound1Handler()));
connect(sound2Timer, SIGNAL(timeout()), this, SLOT(sound2Handler()));
SLOTS:
void Keypad::sound1Handler()
{
// Sound a 250mS chirp
SOUND_BLAST(0, &sound1_t);
}
// Public SLOT, Called by sound2Timer()
// Sounds a single 125mS Beep
void Keypad::sound2Handler()
{
// Emit a Single 125mS chirp
SOUND_BLAST(0, &sound2_t);
}
The Timer is mostly accurate, but it is not exactly 2Hz or 4Hz all the time. To improve the accuracy I was thinking of using a faster timer of say 25mS and letting it run, and every time it accumulates to 250mS or 125mS then sound the beep. However, I am not sure if this would make it more accurate.
Should I measure execution time with QElapsedTimer() and subtract the overhead to sound1Timer, and sound2Timer intervals? Is there a better way to do this?
The accuracy of the timer is limited by the operating system. The Qt library uses operating system timers "under the covers".
If you need high accuracy I would have a timer subroutine that reads a hardware based clock to establish the timing of events. You'll need to dig into your operating system documentation to get the details.
Related
Currently I'm setting a separate hardware timer to the system time periodically to trigger timed interrupts. It's working fine but for elegance sake, but I wondered if it was possible to attach an interrupt directly to the system time
The events are pretty fast: one every 260 microseconds
ESP32 has a few clocks used for system time. The default full power clock is an 80 MHz called APB_CLK. But even the slow RTC clock has 6.6667 μs resolution. (Documentation here: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/system_time.html)
I have a GPS module that I use to update the system time periodically using adjtime(3). The advantage of that being that it gradually adjusts the system time monotonically. Also system time calls are thread safe
I'm using the Arduino IDE, so my knowledge of accessing registers and interrupts directly is poor. Here's a semi boiled down version of what I'm doing. Bit banging a synchronized digital signal. Rotating in 160 bit pages that are prepped from the other core. It's not all of my code, so something not important might be missing:
#define CPU_SPEED 40
hw_timer_t* timer = NULL;
PageData pages[2];
PageData* timerCurrentPage = &pages[0];
PageData* loopCurrentPage = &pages[1];
TaskHandle_t prepTaskHandle;
volatile int bitCount = 0;
void IRAM_ATTR onTimer() {
int level = timerCurrentPage->data[bitCount];
dac_output_voltage(DAC_CHANNEL_1, level?high:low);
bitCount++;
if(bitCount<160) {
timerAlarmWrite(timer, (timerCurrentPage->startTick+timerCurrentPage->ticksPerPage*bitCount), false);
} else {
if(timerCurrentPage == &pages[0]) timerCurrentPage = &pages[1];
else timerCurrentPage = &pages[0];
bitCount = 0;
timerAlarmWrite(timer, (timerCurrentPage->startTick), false);
vTaskResume(prepTaskHandle);
}
}
uint64_t nowTick() {
timeval timeStruct;
gettimeofday(&timeStruct, NULL);
uint64_t result = (uint64_t)timeStruct.tv_sec*1000000UL + (uint64_t)timeStruct.tv_usec;
return result;
}
void gpsUpdate(uint64_t micros) {
int64_t now = nowTick();
int64_t offset = micros - now;
timeval adjustStruct = {0,offset};
adjtime(&adjustStruct,NULL);
}
void setup() {
setCpuFrequencyMhz(CPU_SPEED);
timer = timerBegin(0, CPU_SPEED, true);
timerWrite(timer, nowTick());
timerAttachInterrupt(timer, &onTimer, true);
setPage(&pages[0]);
xTaskCreatePinnedToCore(
prepLoop, /* Task function. */
"Prep Task", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
&prepTaskHandle, /* Task handle to keep track of created task */
1); /* pin task to core 0 */
timerAlarmWrite(timer, (timerCurrentPage->startTick), false);
}
//On Core 1
void prepLoop() {
while(1) {
vTaskSuspend(NULL); //prepTaskHandle
timerWrite(timer, nowTick());
if(loopCurrentPage == &pages[0]) loopCurrentPage = &pages[1];
else loopCurrentPage = &pages[0];
setPage(loopCurrentPage);
}
}
I find on the web this class to implement a callback function that asynchronously do some work while I'm on the Main thread. This is the class:
#include "callbacktimer.h"
CallBackTimer::CallBackTimer()
:_execute(false)
{}
CallBackTimer::~CallBackTimer() {
if( _execute.load(std::memory_order_acquire) ) {
stop();
};
}
void CallBackTimer::stop()
{
_execute.store(false, std::memory_order_release);
if( _thd.joinable() )
_thd.join();
}
void CallBackTimer::start(int interval, std::function<void(void)> func)
{
if( _execute.load(std::memory_order_acquire) ) {
stop();
};
_execute.store(true, std::memory_order_release);
_thd = std::thread([this, interval, func]()
{
while (_execute.load(std::memory_order_acquire)) {
func();
std::this_thread::sleep_for(
std::chrono::milliseconds(interval)
);
}
});
}
bool CallBackTimer::is_running() const noexcept {
return ( _execute.load(std::memory_order_acquire) &&
_thd.joinable() );
}
The problem here is that if I put a job to be done every millisecond I don't know why but it is repeated every 64 milliseconds and not every 1 millisecond, this snippet get an idea:
#include "callbacktimer.h"
int main()
{
CallBackTimer cBT;
int i = 0;
cBT.start(1, [&]()-> void {
i++;
});
while(true)
{
std::cout << i << std::endl;
Sleep(1000);
}
return 0;
}
Here I should see on the Standard Output: 1000, 2000, 3000, and so on. But it doesn't...
It's quite hard to do something on a PC in a 1ms interval. Thread scheduling happens at 1/64s, which is ~16ms.
When you try to sleep for 1 ms, it will likely sleep for 1/64s instead, given that no other thread is scheduled to run. As your main thread sleeps for one second, your callback timer may run up to 64 times during that interval.
See also How often per second does Windows do a thread switch?
You can try multimedia timers which may go down to 1 millisecond.
I'm trying to implement a chronometer in qt which should show also the microsecondo
Well, you can show microseconds, I guess. But your function won't run every microsecond.
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?
My QT application relies upon TimerEvent (startTimer/killTimer) to animation GUI components. Recently, however, I compiled and ran my app on my Mac laptop (as opposed to the Windows desktop computer I was developing on) and found that now everything appears to run/update at half the speed it usually does.
The application is not lagging, it simply appears that the update rate is less frequent than what is was originally. What should I do to guarantee consistent timing with the application on all platforms?
Alternatively, should I be using a different feature for temporary timer events? I would prefer not to, as TimerEvent is unbelievably convenient for integrating update cycles into Widgets, but would be interested if they provide consistent timing.
(basic example code for context):
// Once MyObject is created, counts to 20.
// The time taken is noticeably different on each platform though.
class MyObject: public QObject {
public:
MyObject() {
timerId = startTimer(60);
}
protected:
void timerEvent(QTimerEvent* event) {
qDebug() << (counter++);
if(counter == 20) {
killTimer(timerId);
}
Object::timerEvent(event);
}
private:
int timerId = -1, counter = 0;
}
You are likely seeing problems due to accuracy. QTimer's accuracy varies on different platforms:
Note that QTimer's accuracy depends on the underlying operating system and hardware. The timerType argument allows you to customize the accuracy of the timer. See Qt::TimerType for information on the different timer types. Most platforms support an accuracy of 20 milliseconds; some provide more. If Qt is unable to deliver the requested number of timer events, it will silently discard some.
You could try passing Qt::PreciseTimer to startTimer (the default is Qt::CoarseTimer), but additionally I recommend checking the current timestamp against some start time or against the timestamp of the previous tick. This will allow you to adjust how you handle the varying amounts of time between timer events. This is not dissimilar to how time steps are sometimes handled in games.
For example:
class MyObject: public QObject {
public:
MyObject() {
timerId = startTimer(60, Qt::PreciseTimer);
startTime = std::chrono::steady_clock::now();
}
protected:
void timerEvent(QTimerEvent* event) {
qDebug() << (counter++);
if(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - startTime) / 60 >= 20) {
killTimer(timerId);
}
Object::timerEvent(event);
}
private:
int timerId = -1, counter = 0;
std::chrono::steady_clock::time_point startTime;
}
Another example using QElapsedTimer:
class MyObject: public QObject {
public:
MyObject() {
timerId = startTimer(60, Qt::PreciseTimer);
elapsedTimer.start();
}
protected:
void timerEvent(QTimerEvent* event) {
qDebug() << (counter++);
if(elapsedTimer.elapsed() / 60 >= 20) {
killTimer(timerId);
}
Object::timerEvent(event);
}
private:
int timerId = -1, counter = 0;
QElapsedTimer elapsedTimer;
}
In a separate thread (std::thread), I have an event loop that waits on xcb_wait_for_event. When the program exits, I'd like to shut things down nicely by interrupting (I have a solution that sets a thread-local variable, and checkpoints in the loop throw an exception), and then joining my event thread into the main thread. The issue is xcb_wait_for_event; I need a way to return from it early, or I need an alternative to the function.
Can anyone suggest a solution? Thanks for your help!
I believe I've come up with a suitable solution. I've replaced xcb_wait_for_event with the following function:
xcb_generic_event_t *WaitForEvent(xcb_connection_t *XConnection)
{
xcb_generic_event_t *Event = nullptr;
int XCBFileDescriptor = xcb_get_file_descriptor(XConnection);
fd_set FileDescriptors;
struct timespec Timeout = { 0, 250000000 }; // Check for interruptions every 0.25 seconds
while (true)
{
interruptible<std::thread>::check();
FD_ZERO(&FileDescriptors);
FD_SET(XCBFileDescriptor, &FileDescriptors);
if (pselect(XCBFileDescriptor + 1, &FileDescriptors, nullptr, nullptr, &Timeout, nullptr) > 0)
{
if ((Event = xcb_poll_for_event(XConnection)))
break;
}
}
interruptible<std::thread>::check();
return Event;
}
Making use of xcb_get_file_descriptor, I can use pselect to wait until there are new events, or until a specified timeout has occurred. This method incurs negligible additional CPU costs, resting at a flat 0.0% (on this i7). The only "downside" is having to wait a maximum of 0.25 seconds to check for interruptions, and I'm sure that limit could be safely lowered.
A neater way would be to do something like this (the code snippet is extracted from some code I am currently working on):
void QXcbEventQueue::sendCloseConnectionEvent() const {
// A hack to close XCB connection. Apparently XCB does not have any APIs for this?
xcb_client_message_event_t event;
memset(&event, 0, sizeof(event));
event.response_type = XCB_CLIENT_MESSAGE;
event.format = 32;
event.sequence = 0;
event.window = m_connection->clientLeader();
event.type = m_connection->atom(QXcbAtom::_QT_CLOSE_CONNECTION);
event.data.data32[0] = 0;
xcb_connection_t *c = m_connection->xcb_connection();
xcb_send_event(c, false, m_connection->clientLeader(),
XCB_EVENT_MASK_NO_EVENT, reinterpret_cast<const char *>(&event));
xcb_flush(c); }
For _QT_CLOSE_CONNECTION use your own atom to signal an exit and in my case clientLeader() is some invisible window that is always present on my X11 connection. If you don't have any invisible windows that could be reused for this purpose, create one :)
With this you can terminate the thread with xcb_wait_for_event when you see this special event arriving.