So, the main loop of my game is based on a SDL_WaitEvent type, where it waits for the user to enter new letters while trying to discover a random word. My game need this to work properly but it looks like SDL_WaitEvent stays idle until user press something. The problem is I need my timer to continuosly refresh in order for the player to keep track of it, but when the game reaches the event loop, my timer stays idle and I am not able to find a away to keep it refreshing, any tips would be very appreciated.
Summarizing:
Timer starts: 59 (seconds)
.
.
.
It only will refresh and show the time elapsed when and IF I press something.
SDL_AddTimer() with a callback that uses SDL_PushEvent() to post a user message to the event queue:
/* Start the timer; the callback below will be executed after the delay */
Uint32 delay = (33 / 10) * 10; /* To round it down to the nearest 10 ms */
SDL_TimerID my_timer_id = SDL_AddTimer(delay, my_callbackfunc, my_callback_param);
...
Uint32 my_callbackfunc(Uint32 interval, void *param)
{
SDL_Event event;
SDL_UserEvent userevent;
/* In this example, our callback pushes an SDL_USEREVENT event
into the queue, and causes our callback to be called again at the
same interval: */
userevent.type = SDL_USEREVENT;
userevent.code = 0;
userevent.data1 = NULL;
userevent.data2 = NULL;
event.type = SDL_USEREVENT;
event.user = userevent;
SDL_PushEvent(&event);
return(interval);
}
Related
I want to execute below code only once. Can I use on timer event to execute only once? If yes how can I use on message event inside on timer event ?
on message *
{
if (this.id = "X")
{
setTimer(MyTimer, 10000);
i = snprintf(buffer, elcount(buffer),"X is there\n");
filePutString(buffer, elcount(buffer), readHandle);
}
else
{
i = snprintf(buffer, elcount(buffer),"X is not there with ID: %d\n",this.id );
filePutString(buffer, elcount(buffer), readHandle_01);
}
I want to execute below code only once.
You cant!
The on message * event is called everytime when a message is received on the bus.
You can add an additional if statement to check if a message is already received. Doing so, you can write code that is executed when the first message is received:
variables
{
int thisIsTheFirstMessage = 1;
}
on message *
{
if(thisIsTheFirstMessage)
{
thisIsTheFirstMessage = 0;
/* Put your code here */
}
}
If yes how can I use on message event inside on timer event?
The on timer event is called whenever a timer expires, the on message event is called whenever a message is received.
What do you think under which circumstances a "combination" of both events would be called?
When a timer expires and a message is received in exactly the same microsecond?
The probability that this happens is close to zero.
For this reason, programming languages that support events (CAPL, JavaScript but also some libraries for C++) do not support combining two events.
The only thing that you can do is to combine two events yourself.
Example:
on timer myTimer
{
timerDidNotExpireYet = 0;
if(messageHasNotBeenReceivedYet)
{
/* Code will be executed when the timer
* expires before the first message */
}
}
on message *
{
messageHasNotBeenReceivedYet = 0;
if(timerDidNotExpireYet)
{
/* Code will be executed when a message
* is received but the timer has not
* expired, yet */
}
}
Your question was tagged with: c#
If you want to insert a ".NET node" instead of CAPL code into CANoe, the principle is the same.
Your question was tagged with: c
Why did you tag your question with the "C" tag?
We have several tasks running on an STM32 MCU. In the main.c file we call all the init functions for the various threads. Currently there is one renewing xTimer to trigger a periodic callback (which, at present, does nothing except print a message that it was called). Declarations as follows, outside any function:
TimerHandle_t xMotorTimer;
StaticTimer_t xMotorTimerBuffer;
EventGroupHandle_t MotorEventGroupHandle;
In the init function for the thread:
xMotorTimer = xTimerCreateStatic("MotorTimer",
xTimerPeriod,
uxAutoReload,
( void * ) 0,
MotorTimerCallback,
&xMotorTimerBuffer);
xTimerStart(xMotorTimer, 100);
One thread starts an infinite loop that pauses on an xEventGroupWaitBits() to determine whether to enter an inner loop, which is then governed by its own state:
DeclareTask(MotorThread)
{
bool done = false;
EventBits_t event;
for (;;)
{
Packet * pkt = NULL;
event = xEventGroupWaitBits( MotorEventGroupHandle,
EVT_MOTOR_START | EVT_MOTOR_STOP, // EventBits_t uxBitsToWaitFor
pdTRUE, // BaseType_t xClearOnExit
pdFALSE, // BaseType_t xWaitForAllBits,
portMAX_DELAY //TickType_t xTicksToWait
);
if (event & EVT_MOTOR_STOP)
{
MotorStop(true);
}
if (event & EVT_MOTOR_START)
{
EnableMotor(MOTOR_ALL);
done = false;
while (!done && !abortTest)
{
xQueueReceive(motorQueue, &pkt, portMAX_DELAY);
if (pkt == NULL)
{
done = true;
} else {
done = MotorExecCmd(pkt);
done = ( uxQueueMessagesWaiting(motorQueue) == ( UBaseType_t ) 0);
FreePacket(pkt);
}
}
}
}
}
xEventGroupWaitBits() fires successfully once, the inner loop enters, then exits when the program state meets the expected conditions. The outer loop repeats as it should, but when it arrives again at the xEventGroupWaitBits() call, it crashes almost instantly. In fact, it crashes a few lines down into the wait function, at a call to uxTaskResetEventItemValue(). I can't even step the debugger into the function, as if calling a bad address. But if I check the disassembly, the memory address for the BL instruction hasn't changed since the previous loop, and that address is valid. The expected function is actually there.
I can prevent this chain of events happening altogether by not calling that xTimerStart() and leaving everything else as-is. Everything runs just fine, so it's definitely not xEventGroupWaitBits() (or at least not just that). We tried switching to xEventGroupGetBits() and adding a short osDelay to the loop just as an experiment. That also froze the whole system.
So, main question. Are we doing something FreeRTOS is not meant to do here, using xEventGroupWaitBits() with xTimers running? Or is there supposed to be something between xEventGroupWaitBits() calls, possibly some kind of state reset that we've overlooked? Reviewing the docs, I can't see it, but I could have missed a detail. The
I'm writing Conways game of life in C with SDL. The game logic and everything works fine but I want to have it when you press p for example that the game automatically updates until p is pressed again and the loop stops. Somehow it only repeats once and doesn't even register the second time p is pressed.
else if (e.key.keysym.sym == SDLK_p){
bool stop = false;
while (!stop){
nextEpoch();
updateGame(window, renderer, r);
msleep(500);
if (e.type == SDL_KEYDOWN){
if (e.key.keysym.sym == SDLK_p){
stop = true;
printf("s\n");
}
}
}
}
It doesn't register that p is pressed when it in the while-loop.
Here's the full code: https://gist.github.com/PhilippRados/2df8760cc55822c2eac62addafb24403
As already pointed out by someone else in the comments section, you are not updating e in the inner loop. If you want to update e with a new event, you must call SDL_PollEvent( &e ) again to fill it with a new event.
In your linked code, you seem to be attempting to implement a new state of your program outside the main event loop, which represents the running state of the program, whereas the main event loop represents the paused state of the program. That way, you effectively have two separate event loops, one for each state of the program. While it is possible to make your program work this way, I don't recommend it.
For example, the way you have designed your program, your program won't respond to SDL_QUIT events in the running state. It will only do so in the paused state.
Therefore, it would make more sense to have a single event loop for both the running and the paused states of your program.
I don't recommend that you call usleep or SDL_Delay for waiting until it is time to render the next frame, as your program will not be responding to user input during this time. Especially since you have a very low frame rate of 2 frames per second, this means that it will take up to half a second for your program to respond to user input (for example if the user resizes the window or attempts to close it). Instead, I recommend that you set up a timer using SDL_AddTimer. You can program the timer callback function to give you a SDL_USEREVENT event twice per second. That way, when you receive this event, you will know that it is time to update the game and render the next frame. While waiting for this event, your program will still be able to respond to other events.
Note that in order to use SDL timers, you must initialize the corresponding subsystem using the SDL_INIT_TIMER flag when calling SDL_Init. Strangely, your linked code does not seem to call SDL_Init at all, so I am surprised that your code works at all. According to the documentation, you should call SDL_Init like this:
SDL_Init( SDL_INIT_TIMER | SDL_INIT_VIDEO );
Also, calling SDL_PollEvent in a loop seems like a big waste of CPU resources, as your CPU usage will likely be 100% although you are effectively doing nothing most of the time. I recommend that you call SDL_WaitEvent instead, so that the thread will sleep until it receives a new event to respond to.
Another thing worth noting is that when handling an SDL_MOUSEBUTTONDOWN event, it does not seem appropriate to use the result of SDL_GetMouseState to determine the coordinates of the mouse click, as that function will return the current mouse coordinates and not the coordinates at the time of the click. Therefore, it would be more appropriate to read these coordinates from the SDL_MouseButtonEvent structure.
Here is an example of how you could rewrite your event loop to use SDL_WaitEvent instead of SDL_PollEvent and to support both a running and a paused state in the main event loop.
Uint32 my_callbackfunc( Uint32 interval, void *param )
{
SDL_Event e;
e.user.type = SDL_USEREVENT;
e.user.code = 0;
e.user.data1 = NULL;
e.user.data2 = NULL;
SDL_PushEvent( &e );
return interval;
}
int main (int argc, char** argv)
{
[...]
//set timer to trigger twice per second
SDL_TimerID timer = SDL_AddTimer( 500, my_callbackfunc, NULL );
if ( timer == 0 ) {
//TODO: handle error
return EXIT_FAILURE;
}
//start game in a paused state
bool paused = true;
while ( SDL_WaitEvent( &e ) ) {
switch ( e.type ) {
case SDL_QUIT:
goto quit_game;
case SDL_WINDOWEVENT:
//rerender in case of window state change
updateGame( window, renderer, r );
break;
case SDL_USEREVENT:
if ( !paused ) {
nextEpoch();
updateGame(window, renderer, r);
}
break;
case SDL_MOUSEBUTTONDOWN:
mouseX = getNearestMultiple( e.button.x ) / RECT_SIZE;
mouseY = getNearestMultiple( e.button.y) / RECT_SIZE;
if ( Field[mouseX][mouseY] ) {
//Deactivate cell
Field[mouseX][mouseY] = false;
updateGame(window,renderer,r);
}
else {
//activate cell at position x,y
Field[mouseX][mouseY] = true;
updateGame(window,renderer,r);
}
break;
case SDL_KEYDOWN:
switch ( e.key.keysym.sym ) {
case SDLK_SPACE:
if ( paused ) {
nextEpoch();
updateGame(window, renderer, r);
}
break;
case SDLK_r:
memset(Field,0,sizeof(Field[0][0]) * WIDTH * HEIGHT);
memset(nextState,0,sizeof(nextState[0][0]) * WIDTH * HEIGHT);
updateGame(window,renderer, r);
break;
case SDLK_p:
paused = !paused;
}
}
}
quit_game:
SDL_DestroyWindow(window);
SDL_Quit();
return EXIT_SUCCESS;
}
Let's consider a multi-sports race event like a triathlon. In this event when a person completes one activity (running, swimming, cycling etc) they immediately start a new activity after it. Suppose I have a device that continuously monitors the activity of the person. If you see the code, in "main()" function the volatile variable "activity" gets input from the device.
The race was started 2 Hr before.
My aim is to find out from how long till the current moment the person is in that particular activity. Say from past 1000 seconds the person is in running activity and earlier he/she was doing "cycling" (this could be anything in the general case). Also, the point is that the end time of previous activity is the start time current activity.
The "triathlonTim()" function is called after every 1 sec continuously. When I calculate time as per my code, it's coming out to be 1 sec but actually it should be 1000 seconds. Here, time(NULL) and "stateTim" are updating continuously. "StateTim" variable must only be updated at the point when the person stops one activity and start other activity. So how do I fix it out? Any other idea or hint can also be useful to me.
#include<stdio.h>
#include<time.h>
#define CYCLING 1
#define RUNNING 2
#define SWIMMING 3
static int state ;
static int prevState ;
int stateTim;
void triathlonTim(int activity)
{
int activtyTimDur ;
if(activity == 10)
{
printf("doing Cycling\n\r");
state = CYCLING;
}
else if(activity == 20)
{
printf("doing Running\n\r");
state = RUNNING;
}
else if(activity == 30)
{
printf("doing Swimming\n\r");
state = SWIMMING;
}
if(prevState != state)
{
activtyTimDur = time(NULL) - stateTim;
stateTim =time(NULL);
printf("Activity Time Duration = %d\n\r", activtyTimDur);
}
}
int main(void)
{
volatile int activity;
while(1)
{
triathlonTim(activity);
sleep(1);
}
return 0;
}
You need to set prevState whenever the state changes. Otherwise, every call will be treated as a state change.
if(prevState != state)
{
activtyTimDur = time(NULL) - stateTim;
stateTim =time(NULL);
prevState = state;
printf("Activity Time Duration = %d\n\r", activtyTimDur);
}
I'm writing a kernel module for linux, and I want my timer to re-set itself. To this end, I thought to call mod_timer from inside the timer's callback function, as shown:
static void sched_send(unsigned long data)
{
send_now();
mod_timer(&test_timer, jiffies+(get_interval()*HZ));
}
static void timer_start(void)
{
set_log_msg("Meep meep!");
test_timer.function = sched_send;
test_timer.expires = jiffies + HZ*get_interval();
}
However, I've read mod_timer deletes the timer and re-adds it. Will it cause problems? If so, is there a better way to create a repeating timer for kernel modules?
It is safe to execute mod_timer from the timer callback.
From the kernel source (kernel/timer.c):
/* mod_timer(timer, expires) is equivalent to:
*
* del_timer(timer); timer->expires = expires; add_timer(timer);
* ...
*/
As for del_timer,
/*
* del_timer - deactive a timer.
* #timer: the timer to be deactivated
*
* del_timer() deactivates a timer - this works on both active and inactive
* timers.
* ...
*/
As noted by Peter, you need to invoke add_timer anytime you want to start/restart the timer.
Your function timer_start() will have to call add_timer() after it sets up the function and the expiration time. Once the timer function triggers, your timer is no longer active, so all you have to do is reset the .expires field to your new value and call add_timer() again. Be sure you provide a clean way to stop rescheduling the timer, for example on module unload.
send_now();
if(!terminate_timer) {
test_timer.expires = jiffies + HZ*get_interval();
add_timer(&test_timer);
}