I need to notify some objects to clear their cache at new day begins. So, I could create QTimer or something similar and check every ms that now midnight +-5ms or not, but it's not a good idea for me.
Is there(in QT) any standard mechanisms to get notified about this event without allocating any new object? Something static or living since application's initialization like qApp?
What would you do in situation like this where you need to do something at 00:00?
UPD:
I'm looking for fast enough solution. Fast means that I need to clear container in slot as quick as it possible, 'cause since midnight data in the container become invalid. So, there is some other timer which shots every 100ms for instance and it trying to get data from container. I need to clear container with invalid data right before any possible try of getting access.
The simplest solution does indeed utilize a timer. Polling for the passage of time in not only unnecessary, but would be horrible performance-wise. Simply start the actions when the midnight strikes:
static int msecsTo(const QTime & at) {
const int msecsPerDay = 24 * 60 * 60 * 1000;
int msecs = QTime::currentTime().msecsTo(at);
if (msecs < 0) msecs += msecsPerDay;
return msecs;
}
// C++11
void runAt(const std::function<void> & job, const QTime & at, Qt::TimerType type = Qt::VeryCoarseTimer) {
// Timer ownership prevents timer leak when the thread terminates.
auto timer = new QTimer(QAbstractEventDispatcher::instance());
timer->start(msecsTo(at), type);
QObject::connect(timer, &QTimer::timeout, [=job, &timer]{
job();
timer->deleteLater();
});
}
runAt([&]{ object->member(); }, QTime(...));
// C++98
void scheduleSlotAt(QObject * obj, const char * member, const QTime & at, Qt::TimerType type = Qt::VeryCoarseTimer) {
QTimer::singleShot(msecsTo(at), type, obj, member);
}
class MyObject : public QObject {
Q_OBJECT
void scheduleCleanup() {
scheduleSlotAt(this, SLOT(atMidnight()), QTime(0, 0));
}
Q_SLOT void atMidnight() {
// do some work here
...
scheduleCleanup();
}
public:
MyObject(QObject * parent = 0) : QObject(parent) {
...
scheduleCleanup();
}
};
there is some other timer which shots every 100ms for instance and it trying to get data from container.
Since both of these timers presumably run in the same thread, they execute serially and it doesn't matter how much "later" either one is. They won't both run at the same time.
Related
I am writing code for a school project that will be used for a Chromebook charging station with security. The problem I am having now is when I am detecting if a Chromebook is actually in the slot after the user has been assigned one, I am using a rocker switch to simulate this but when I am declaring the pin to the rocker, the arduino verfier comes up with that
"'slot1' does not name a type".
Code is below:
//class
class Chromebook_slot {
public:
String Name = "";
String RFID_tag = "";
int rocker = 0;
boolean chromebook_in = false;
//class function to check if chromebook is in.
//if not, redirect already to reassigning so chromebook slot is entered as open and free.
void set_if_in()
{
int momen_1_state = digitalRead(momen_1);
int momen_2_state = digitalRead(momen_2);
// the button has been pushed down and the previous process has been completed
// eg. servos would have been reset if there was a previous user
if (momen_1_state == HIGH || momen_2_state == HIGH)
{
chromebook_in = digitalRead(this->rocker);
if (chromebook_in == 0)
{
re_assigning();
}
else
{
return;
}
}
}
};
//this is now outside the class..
//class declarations
Chromebook_slot slot1;
Chromebook_slot slot2;
//variables for rocker switches which will act for detecting chromebooks.
// in my final version, this will replaced by a photoresistor and laser.
slot1.rocker = 3;
slot2.rocker = 2;
Where the function re_assigning() is a separate function declared further in the code and just resets the slot as open for future use.
slot1.rocker = 3;
slot2.rocker = 2;
These are statements that cannot be at the top level of a C++ (or .ino) file. They need to be inside of a function. What's happening is the compiler is looking looking at the slot1 identifier through the lens of potential valid constructions. It sees an identifier, and about the only thing that could legally exist at this point in the code that starts with an identifier like that is some declaration, e.g. int a = 7;, or more abstractly some_type some_more_stuff. So it expects slot1 to be a type, which it isn't, hence the message.
If you want an assignment like those to happen early on in an Arduino program, the simplest thing you could do is put them in setup():
void setup() {
slot1.rocker = 3;
slot2.rocker = 2;
// ...
}
Or, you'd make these part of the Chromebook_slot's constructor, such that they could be given in slot1 and slot2's declaration:
class Chromebook_slot {
public:
Chromebook_slot(int rocker_init_value) {
rocker = rocker_init_value;
}
// ...
Or in a maybe less familiar but more proper form, using the constructor's initialization list:
class Chromebook_slot {
public:
Chromebook_slot(int rocker_init_value)
: rocker(rocker_init_value) {}
// ...
Once you have a constructor for Chromebook_slot, your variables can become:
Chromebook_slot slot1(3);
Chromebook_slot slot2(2);
In a QT app, I want to start a loop inside a qthread that reads 2 different sounds (it's a metronome).
I have a function with my process. I want to start it when I click on a button and stop it with another one.
The problem is, when I start it, my app doesn't respond, I can't click on the stop button. I have to stop the app.
#include <QSound>
#include <QEventLoop>
ClickThread::ClickThread(): highClickFile("://high_click.wav"), lowClickFile("://low_click.wav"), isRunning(false)
{
this->highClick = new QSound(highClickFile);
this->lowClick = new QSound(lowClickFile);
this->setPeriod(120);
}
void ClickThread::run()
{ QTimer *timer = new QTimer();
timer ->moveToThread(this);
timer->connect(timer, SIGNAL(timeout()),this, SLOT(process()));
timer ->start();
exec();
}
void ClickThread::process(){
highClick->play();
QThread::msleep(period);
highClick->stop();
lowClick->play();
QThread::msleep(period);
lowClick->stop();
lowClick->play();
QThread::msleep(period);
lowClick->stop();
lowClick->play();
QThread::msleep(period);
lowClick->stop();
}
void ClickThread::setIsRunning(bool set)
{
this->isRunning=set;
}
void ClickThread::setPeriod(unsigned long bpm)
{
this->period = 60000/bpm;
}
Thx for your answers
Stop using QTimer.
The QTimer you have currently is default to a timeout interval of 0. That is going to stuff up the event queue with infinite calls to process(), which will cause serious problems.
You should use this while loop instead:
stopPlaying = false;
while(stopPlaying == false)
{
process();
}
The boolean stopPlaying variable should be declared in your "ClickThread" class definition and used by your stop button to cause the thread to drop out of the loop, terminating the thread.
First time writing an AsyncTask and I seem to have a subtle design flaw that prevents both ProgressDialog, ProgressBar, and even Log.d() from working properly. I suspect that somehow I am not actually creating a new thread/task.
Short: the symptoms
A ProgressDialog is created in the constructor, and the code orders Android to show it in onPreExecute(), but the dialog never shows.
onProgressUpdate() is supposed to execute whenever I call publishProgress() from within doInBackground(), correct? Well, it doesn't. Instead, it executes when doInBackground() completes.
Long: investigations
Things I have verified through the emulator and, when possible, on a phone:
onPreExecute() is definitely called
the progress bar is not reset until after doInBackground() completes
update_dialog.show() is definitely executed, but the dialog does not appear unless I remove the .dismiss() in onPostExecute(); I imagine dialog is, like the progress bar, not shown until after doInBackground() completes, but is naturally immediately dismissed
the code will happily show dialogs when no computation is involved
doInBackground() definitely invokes publishProgress()
when it does, onProgressUpdate() does not execute immediately! that is, I have a breakpoint in the function, and the debugger does not stop there until after doInBackground() completes! (perhaps this is a phenomenon of the debugger, rather than doInBackground(), but I observe the same symptoms on a mobile device)
the progress bar gets updated... only after doInBackground() completes everything
similarly, the Log.d() data shows up in Android Monitor only after doInBackground() completes everything
and of course the dialog does not show up either in the emulator or on a device (unless I remove .dismiss() from onPostExecute())
Can anyone help find the problem? Ideally I'd like a working dialog, but as Android has deprecated that anyway I'd be fine with a working progress bar.
Code
Here are the essentials, less the details of computation &c.:
Where I call the AsyncTask from the main thread:
if (searching) { // this block does get executed!
Compute_Task my_task = new Compute_Task(overall_context, count);
my_task.execute(field, count, max_x, max_y);
try { result = my_task.get(); } catch (Exception e) { }
}
The AsyncTask itself:
private class Compute_Task extends AsyncTask<Object, Integer, Integer> {
public Compute_Task(Context context, int count) {
super();
current_positions = 0;
update_dialog = new ProgressDialog(context);
update_dialog.setIndeterminate(true);
update_dialog.setCancelable(false);
update_dialog.setTitle("Thinking");
update_dialog.setMessage("Please wait");
}
protected void onPreExecute() {
super.onPreExecute();
update_dialog.show();
ProgressBar pb = ((ProgressBar) ((Activity) overall_context).findViewById(R.id.progress_bar));
pb.setMax(base_count);
pb.setProgress(0);
}
protected void onPostExecute() {
super.onPostExecute();
update_dialog.dismiss();
}
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
ProgressBar pb = ((ProgressBar) ((Activity) overall_context).findViewById(R.id.progress_bar));
pb.setMax(base_count);
pb.incrementProgressBy(1);
Log.d(tag, values[0].toString());
}
protected Integer doInBackground(Object... params) {
Integer result = compute_scores(
(boolean[][]) params[0], (Integer) params[1], (Integer) params[2], (Integer) params[3], 0)
);
return result;
}
public int compute_scores(boolean[][] field, int count, int max_x, int max_y, int level) {
int result, completed = 0;
switch(count) {
// LOTS of computation goes on here,
// including a recursive call where all params are modified
if (level == 0)
publishProgress(++completed);
}
}
ProgressDialog update_dialog;
}
Turns out this is basically the same issue as the one given here. The "fatal" line is this one:
try { result = my_task.get(); } catch (Exception e) { }
Apparently this puts the UI thread into deep sleep. One should not use get() with an AsyncTask unless one is willing to suspend the UI thread. We have to perform a little magic in onPostExecute() instead.
Although it turns out that this was a duplicate, I didn't find it until after I wrote it, because I didn't realize the thread was blocking.
I am making a super simple watchface for the pebble using SDK 2. The watchface compiles and install but the clock does not update. I have attached my code below. Any ideas?
#include <pebble.h>
static Window *s_main_window;
static TextLayer *s_time_layer;
static TextLayer *s_date_layer;
static GFont s_time_font;
static BitmapLayer *s_background_layer;
static GBitmap *s_background_bitmap;
static void update_time() {
// Get a tm structure
time_t temp = time(NULL);
struct tm *tick_time = localtime(&temp);
// Create a long-lived buffer
static char buffer[] = ">00:00";
// Write the current hours and minutes into the buffer
if(clock_is_24h_style() == true) {
//Use 2h hour format
strftime(buffer, sizeof(">00:00"), ">%H:%M", tick_time);
} else {
//Use 12 hour format
strftime(buffer, sizeof(">00:00"), ">%I:%M", tick_time);
}
// Display this time on the TextLayer
text_layer_set_text(s_time_layer, buffer);
}
static void update_date(){
time_t temp = time(NULL);
struct tm *tick_time = localtime(&temp);
static char buffer[] = ">00/00/00";
strftime(buffer, sizeof(">00/00/00"), ">%D", tick_time);
text_layer_set_text(s_date_layer, buffer);
}
static void main_window_load(Window *window) {
//Create Gbitmap, then set to created bitmap layer
s_background_bitmap = gbitmap_create_with_resource(RESOURCE_ID_lenny);
s_background_layer = bitmap_layer_create(GRect(0, 0, 144, 168));
bitmap_layer_set_bitmap(s_background_layer, s_background_bitmap);
layer_add_child(window_get_root_layer(window), bitmap_layer_get_layer(s_background_layer));
// Create time TextLayer
s_time_layer = text_layer_create(GRect(5, 90, 144, 50));
text_layer_set_background_color(s_time_layer, GColorClear);
text_layer_set_text_color(s_time_layer, GColorBlack);
text_layer_set_text(s_time_layer, ">00:00");
//Create date TextLayer
s_date_layer = text_layer_create(GRect(5, 115, 144, 50));
text_layer_set_background_color(s_date_layer, GColorClear);
text_layer_set_text_color(s_date_layer, GColorBlack);
text_layer_set_text(s_date_layer, ">00/00/00");
//Create GFont
s_time_font = fonts_load_custom_font(resource_get_handle(RESOURCE_ID_arial25));
//Apply to TextLayer
text_layer_set_font(s_time_layer, s_time_font);
text_layer_set_text_alignment(s_time_layer, GTextAlignmentLeft);
text_layer_set_font(s_date_layer, s_time_font);
text_layer_set_text_alignment(s_date_layer, GTextAlignmentLeft);
// Add it as a child layer to the Window's root layer
layer_add_child(window_get_root_layer(window), text_layer_get_layer(s_time_layer));
layer_add_child(window_get_root_layer(window), text_layer_get_layer(s_date_layer));
// Make sure the time is displayed from the start
update_time();
update_date();
}
static void main_window_unload(Window *window) {
//Unload GFont
fonts_unload_custom_font(s_time_font);
// Destroy TextLayer
text_layer_destroy(s_time_layer);
//Destroy Gbitmap
gbitmap_destroy(s_background_bitmap);
//Destroy BitmapLayer
bitmap_layer_destroy(s_background_layer);
//Destroy datelayer
text_layer_destroy(s_date_layer);
}
static void tick_handler(struct tm *tick_time, TimeUnits units_changed) {
update_time();
}
static void tick_handler_date(struct tm *tick_time, TimeUnits units_changed){
update_date();
}
static void init() {
// Create main Window element and assign to pointer
s_main_window = window_create();
// Set handlers to manage the elements inside the Window
window_set_window_handlers(s_main_window, (WindowHandlers) {
.load = main_window_load,
.unload = main_window_unload
});
// Show the Window on the watch, with animated=true
window_stack_push(s_main_window, true);
// Register with TickTimerService
tick_timer_service_subscribe(MINUTE_UNIT, tick_handler);
tick_timer_service_subscribe(DAY_UNIT, tick_handler_date);
}
static void deinit() {
// Destroy Window
window_destroy(s_main_window);
}
int main(void) {
init();
app_event_loop();
deinit();
}
There is a true type font being used as well as a png. These can be replaced with anything for testing purposes as long as the reference ID's in the code are changed as well. Any help is greatly appreciated. Thanks !
It's because you override checking every minute and updating the time here:
tick_timer_service_subscribe(DAY_UNIT, tick_handler_date);
tick_timer_service_subscribe takes a unit and a function pointer. When you called it the second time you overrode the unit and the function pointer.
Instead you should call it once with MINUTE_UNIT and tick_handler. Then inside tick_handler write a new function called update_date_and_time. This function does what it says, updates the date and the time. You'll unnecessarily update the date most of the time, but that's okay, because you'll correctly update the time.
I am writing a simple task planner and reminder using Qt which will play a sound file when the date and time of any given task matches with the the current date and time.
To implement this, I am running a QThread which checks the task in the list to see if any match the current time and if so, plays the sound file.
This id my original class:
class Task
{
public:
QString ta, desc;
QTime ti;
QDate da;
int pri, diff;
bool ala;
};
This is my Thread Class:
class AlarmCheck : public QThread
{
public:
void setTask(QList<Task>);
void run();
bool isRunning;
QString music;
QTime alarmOffset;
private:
QList<Task> list;
};
My Implementation:
void AlarmCheck::setTask(QList<Task> l)
{
list = l;
}
void AlarmCheck::run()
{
while(isRunning)
{
foreach(Task t, list)
{
if((t.da == QDate::currentDate()) && (t.ti == QTime::currentTime()) && t.ala)
{
Phonon::MediaObject *gaana =
Phonon::createPlayer(Phonon::MusicCategory,
Phonon::MediaSource(music));
gaana->play();
QMessageBox::information(NULL,
"Alarm!!!",
"The time has come for\n"
+ t.ta +
"\n Time to do it!");
gaana->stop();
}
qDebug("Curr = " + QTime::currentTime().toString().toAscii() + " Date = " + QDate::currentDate().toString().toAscii());
qDebug("Task = " + t.ti.toString().toAscii() + " Date = " + t.da.toString().toAscii());
}
sleep(1);
}
}
The thing is that the thread is running perfectly, but the if() condition inside the foreach() loop is never satisfied for some reason. I even checked the individual date/time/alarm setting (t.ala) using qDebugs (as you can see); they are all fine.
Your if statement requires that the date and time match exactly, down to the millisecond. It is unlikely that your loop will evaluate at this exact moment. If you want to maintain similar logic (processing tasks in a loop), you might try sorting them by "next task first" (or perhaps using a queue), then testing in your if statement if the current QDateTime is equal-to-or-greater than the task date/time of the first task.