I wrote a simple 2d tile based game and ran it on 2 computers. On comp1 it's very slow, on comp2 it's lightening fast.
Comp1's cpu is a little slower, but it can play other sdl games (even inside emulaters) and simple 3d games, fast enough.
So I ran the game on both computers using only cpu rendering: both ran at the same speed.
Then I switched to gpu rendering and the 2nd computer went really fast (200+fps) but the first stayed at the same pace, around 20fps.
So I assumed either the hw acceleration is not working on comp1 or the cpu is clogged with my calculations.
I logged all the error handling and can confirm both computers support the hw acceleration and the texture sizes (i know this for a fact because the cpu bound version of the game has no flip and so the character always faces the same way ;)
So then it has to be a slow cpu on the first computer, right? But when I check the cpu stats the game only takes 1,2% cpu, and overall load is around 2% cpu
So the cpu is sitting mostly idle while my game crawls along :(
The game is a few 1000 lines of code now, so here are some of the statements that I think pertain to this problem:
Main game loop:
while (!quit)
{
GameEngine_Tick(gameType->fps, false, 0);
if (SDL_PollEvent(&event) != 0))
{
int windowID = event.window.windowID;
if (event.window.event == SDL_WINDOWEVENT_CLOSE &&
event.window.windowID == screens[0].windowID) quit = true;
switch (event.type)
{
case SDL_KEYDOWN:
if (event.key.keysym.sym == SDLK_LEFT) { Key_Left(); }
if (event.key.keysym.sym == SDLK_RIGHT) { Key_Right();}
if (event.key.keysym.sym == SDLK_UP) { Key_Up(); }
if (event.key.keysym.sym == SDLK_DOWN) { Key_Down(); }
break; // end key_down.
} // switch event type
}
GameEngine_Render();
}
Frame rate limiting in GameEngine_Tick:
void GameEngine_Tick(int fps, bool bIsRegTestStep, Uint8 TDir)
{
unsigned int frametime = 1000 / fps;
unsigned int currentTime;
const Uint8* keystates = SDL_GetKeyboardState(NULL); // do not free.
SDL_PumpEvents(); // upd keystates to get keyboard inputs.
// Get KB input - todo: later GetInputFromSelectedInputDevice (checks kb/xbox etc)
if (keystates[SDL_SCANCODE_LEFT]) GameLeft();
else if (keystates[SDL_SCANCODE_RIGHT]) GameRight();
Sprites_Tick();
// set framerate by waiting if needed.
currentTime = SDL_GetTicks();
if (currentTime - prevTime < (frametime))
{
//Sleep the remaining frame time
if (fps > 0) SDL_Delay((frametime)-(currentTime - prevTime)); /* fps-1 == MAX == no delay*/
}
prevTime = currentTime;
}
create renderer:
ren = nullptr;
if (bForceCPURender == false) ren = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);// | SDL_RENDERER_PRESENTVSYNC);
if (nullptr == ren)
{
if (bForceCPURender == false)
{
Log("Info: SDL_CreateRenderer with SDL_RENDERER_ACCELERATED failed. Trying default.");
}
bForceCPURender = true;
ren = SDL_CreateRenderer(window, -1, 0);
if (nullptr == ren)
{
Log("Info: SDL_CreateRenderer with default also failed.");
SDLDestroy();
return -1;
}
else Logs("Info: success using default renderer.");
}
else Logs("Info: success, using SDL_CreateRenderer with SDL_RENDERER_ACCELERATED.");
Creating textures or surfaces:
spriteMapTexture = SDL_CreateTexture(ren, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET,
x_pixPerCharInStageMap * roomWidthInChars * gameRoomMatrix_w,
y_pixPerCharInStageMap * roomHeightInChars * gameRoomMatrix_h);
// If GPU cannot handle size of stage map: try to do CPU preRendering. (gpu is texture, cpu is surface).
if (NULL == spriteMapTexture || bForceCPUStageRenderAnyway == true)
{
spriteMapSurface = GameEngine_CreateRGBSurface(x_pixPerCharInStageMap * roomWidthInChars * gameRoomMatrix_w, y_pixPerCharInStageMap * roomHeightInChars * gameRoomMatrix_h);
}
while (!quit)
{
GameEngine_Tick(gameType->fps, false, 0);
if (SDL_PollEvent(&event) != 0))
^^ wat
{
// process event
}
GameEngine_Render();
}
Right now you're only processing a single event each frame. Used to be SDL could only buffer 128 events before dropping them, nowadays I think they're up to 64k. So if, for example, you have a high-report-rate gaming mouse (500-1000 Hz sampling) your event queue will get backed up far faster than a regular mouse (125 Hz). Same for any other event type SDL can generate; some systems will have different event generation rates than others.
You want to process every event in the queue before rendering a frame:
while (!quit)
{
GameEngine_Tick(gameType->fps, false, 0);
// NOTE: if -> while
while( SDL_PollEvent(&event) )
{
// process event
}
GameEngine_Render();
}
Related
I am trying to establish UART communication between a PC and a STM32f407-DISC1 board using an arduino nano as a middle man.
The PC sends 'r' to the arduino to indicate a request.
The request is then communicated to the stm32 with a GPIO interrupt, which then should be transmitting 480 bytes of data using HAL_UART_Transmit_IT.
It however sends the data twice, with only a single request made.
The code on the STM32 is generated by STM32CubeMX
Data request made by the arduino
void loop() {
digitalWrite(4, 0); // Clear EXTI11 line.
if (mySerial.available() && received < 480) { // STM32 sending data and is not done.
buff[received] = mySerial.read(); // Append received data to the buffer.
received++;
}
if (received >= 480) { // If the buffer is full
received = 0; // transmit it to PC.
Serial.println(buff);
}
if (Serial.available()) {
if (Serial.read() == 'r') { // PC requests data from the STM32
digitalWrite(4, 1); // Triggers STM32 EXTI11 line.
while (Serial.available()) // Empty the buffer.
Serial.read();
}
}
}
data transmission on the STM32
void EXTI15_10_IRQHandler(void)
{
// Make sure that the interrupt is the good one.
if (HAL_GPIO_ReadPin(data_req_IRQ_GPIO_Port, data_req_IRQ_Pin)) {
if (is_sending_data == FALSE) // If no transmission is happening
should_send_data = TRUE; // raise transmission flag.
}
// IRQ handling stuff...
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef * huart) {
is_sending_data = FALSE; // Transmition is completed, unblock requests.
}
void main(void){
// Init and other stuff...
while (1) {
if (should_send_data == TRUE) { // If data was requested
HAL_GPIO_WritePin(LD5_GPIO_Port, LD5_Pin, GPIO_PIN_RESET);
HAL_UART_Transmit_IT(&huart3, matrice, 480); // Start transmission by interrupt.
is_sending_data = TRUE; // Block requests.
should_send_data = FALSE; // Clear flag.
}
// matrice acquisition stuff here
}
}
Alright so I found a solution, but it involved just rethinking my approach, so sorry for those looking for an answer to this problem.
I removed the arduino middle man by replacing it with a USB to RS232 converter and made UART reception work by interrupt. The STM detects the 'r' character which triggers the data communication.
Here is the interrupt part:
void USART3_IRQHandler(void)
{
if (USART3->SR & UART_IT_RXNE) { // If a byte is received
rxBuff[0] = (uint8_t) (huart3.Instance->DR & (uint8_t) 0xFF); // Read it.
__HAL_UART_FLUSH_DRREGISTER(&huart3); // Clear the buffer to avoid errors.
rx_new_char_flag = TRUE; // Raise the new_char flag.
return; // Stops the IRQHandler from disabling interrupts.
}
}
and the gestion of that in the main
while (1) {
if (rx_new_char_flag == TRUE) {
rx_new_char_flag = FALSE;
if (rxBuff[0] == 'r') {
rxBuff[0] = 0;
HAL_UART_Transmit_IT(&huart3, matrice, 480); // Start transmission by interrupt.
}
}
On the PC side, to optimize performance, instead of waiting for the full 480 bytes, I wait for only one character, if one is received I keep reading the serial port, as shown in the code bellow
int i = 0;
do {
ReadFile(m_hSerial, &temp_rx[i], 1, &dwBytesRead, NULL);
i++;
} while (dwBytesRead > 0 && i < 480);
for (int j = i; j < 480; j++) // If the transmission is incomplete, fill the buffer with 0s to avoid garbage data.
temp_rx[j] = 0;
if(i>=480) // If all the bytes has been received, copy the data in the working buffer.
std::copy(std::begin(temp_rx), std::end(temp_rx), std::begin(m_touch_state));
This works well with pretty decent performance, so that may be a permanent solution to my problem.
We are missing interrupts in an linux embedded system having multi-core running at 1.25GHz.
Background:
kernel version: 2.6.32.27
we have user space processes which need real time performance.
They operate in a 1ms boundary.
That is to say within 1ms they are expected to complete a set of task, which at the max may take about 800uS.
We have a external component FPGA which provides, 1ms and 10ms interrupts to the multi-core processor through GPIO pins configured as edge triggerred interrupts.
These interrupts are handled in kernel driver.
The software architecture is in such a way that the user process, after completing its work will do an ioctl to the GPIO driver.
In this ioctl the driver will put the process to wakeup_interruptible state.
Whenever the next 1ms interrupt is received, the ISR will wakeup the process. This cycle repeats.
Both the 1ms and 10ms interrupts are routed to a single core of the processor using smp_affinity.
Problem:
Sometimes we find that some interrupts are missed.
(ie ISR itself doesnt get invoked).
After 12 to 20ms ISR's are hit normally.
This we are able to understand by profiling the duration between consecutive ISR calls, and having counters incremented first thing in the ISR.
This mostly happens during high system load at process level, and is random and hard to reproduce.
I have attached the skeletal code.
First I have to isolate whether it is a hardware or software problem. As it is a FPGA which is giving the interrupts, we dont have much doubt on the hardware.
Is this kernel freezing? It is the most likely case since the cpu cycles are incrementing.
Can it be a case of cpu freeze due to thermal conditions? If so, then the cpu cycles wouldn't have incremented in first place.
Any pointers to debug/isolate the root cause will be of great help
considering the kernel version we are working on and the profiling/debugging
facilities available in this kernel version.
skeletal code:
/* Build time Configuration */
/* Macros */
DECLARE_WAIT_QUEUE_HEAD(wait);
/** Structure Definitions */
/** Global Variables */
gpio_dev_t gpio1msDev, gpio10msDev;
GpioIntProfileSectorData_t GpioSigProfileData[MAX_GPIO_INT_CONSUMERS];
GpioIntProfileSectorData_t *ProfilePtrSector;
GpioIntProfileData_t GpioProfileData;
GpioIntProfileData_t *GpioIntProfilePtr;
CurrentTickProfile_t TimeStamp;
uint64_t ModuleInitDone = 0, FirstTimePIDWrite = 0;
uint64_t PrevCycle = 0, NowCycle = 0;
volatile uint64_t TenMsFlag, OneMsFlag;
uint64_t OneMsCounter;
uint64_t OneMsIsrTime, TenMsIsrTime;
uint64_t OneMsCounter, OneMsTime, TenMsTime, SyncStarted;
uint64_t Prev = 0, Now = 0, DiffTen = 0, DiffOne, SesSyncHappened;
static spinlock_t GpioSyncLock = SPIN_LOCK_UNLOCKED;
static spinlock_t IoctlSyncLock = SPIN_LOCK_UNLOCKED;
uint64_t EventPresent[MAX_GPIO_INT_CONSUMERS];
GpioEvent_t CurrentEvent = KERN_NO_EVENT;
TickSyncSes_t *SyncSesPtr = NULL;
/** Function Declarations */
ssize_t write_pid(struct file *filep, const char __user * buf, size_t count, loff_t * ppos);
long Gpio_compat_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
static const struct file_operations my_fops = {
write:write_pid,
compat_ioctl:Gpio_compat_ioctl,
};
/**
* IOCTL function for GPIO interrupt module
*
* #return
*/
long Gpio_compat_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
{
int len = 1, status = 0;
uint8_t Instance;
uint64_t *EventPtr;
GpioIntProfileSectorData_t *SectorProfilePtr, *DebugProfilePtr;
GpioEvent_t EventToGive = KERN_NO_EVENT;
pid_t CurrentPid = current->pid;
spin_lock(&IoctlSyncLock); // Take the spinlock
Instance = GetSector(CurrentPid);
SectorProfilePtr = &GpioSigProfileData[Instance];
EventPtr = &EventPresent[Instance];
spin_unlock(&IoctlSyncLock);
if (Instance <= MAX_GPIO_INT_CONSUMERS)
{
switch (cmd)
{
case IOCTL_WAIT_ON_EVENT:
if (*EventPtr)
{
/* Dont block here since this is a case where interrupt has happened
* before process calling the polling API */
*EventPtr = 0;
/* some profiling code */
}
else
{
status = wait_event_interruptible(wait, (*EventPtr == 1));
*EventPtr = 0;
}
/* profiling code */
TimeStamp.CurrentEvent = EventToGive;
len = copy_to_user((char *)arg, (char *)&TimeStamp, sizeof(CurrentTickProfile_t));
break;
default:
break;
}
}
else
{
return -EINVAL;
}
return 0;
}
/**
* Send signals to registered PID's.
*
* #return
*/
static void WakeupWaitQueue(GpioEvent_t Event)
{
int i;
/* some profile code */
CurrentEvent = Event;
// we dont wake up debug app hence "< MAX_GPIO_INT_CONSUMERS" is used in for loop
for (i = 0; i < MAX_GPIO_INT_CONSUMERS; i++)
{
EventPresent[i] = 1;
}
wake_up_interruptible(&wait);
}
/**
* 1ms Interrupt handler
*
* #return
*/
static irqreturn_t gpio_int_handler_1ms(int irq, void *irq_arg)
{
uint64_t reg_read, my_core_num;
unsigned long flags;
GpioEvent_t event = KERN_NO_EVENT;
/* code to clear the interrupt registers */
/************ profiling start************/
NowCycle = get_cpu_cycle();
GpioIntProfilePtr->TotalOneMsInterrupts++;
/* Check the max diff between consecutive interrupts */
if (PrevCycle)
{
DiffOne = NowCycle - PrevCycle;
if (DiffOne > GpioIntProfilePtr->OneMsMaxDiff)
GpioIntProfilePtr->OneMsMaxDiff = DiffOne;
}
PrevCycle = NowCycle;
TimeStamp.OneMsCount++; /* increment the counter */
/* Store the timestamp */
GpioIntProfilePtr->Gpio1msTimeStamp[GpioIntProfilePtr->IndexOne] = NowCycle;
TimeStamp.OneMsTimeStampAtIsr = NowCycle;
GpioIntProfilePtr->IndexOne++;
if (GpioIntProfilePtr->IndexOne == GPIO_PROFILE_ARRAY_SIZE)
GpioIntProfilePtr->IndexOne = 0;
/************ profiling end************/
/*
* Whenever 10ms Interrupt happens we send only one event to the upper layers.
* Hence it is necessary to sync between 1 & 10ms interrupts.
* There is a chance that sometimes 1ms can happen at first and sometimes 10ms.
*
*/
/******** Sync mechanism ***********/
spin_lock_irqsave(&GpioSyncLock, flags); // Take the spinlock
OneMsCounter++;
OneMsTime = NowCycle;
DiffOne = OneMsTime - TenMsTime;
if (DiffOne < MAX_OFFSET_BETWEEN_1_AND_10MS) //ten ms has happened first
{
if (OneMsCounter == 10)
{
event = KERN_BOTH_EVENT;
SyncStarted = 1;
}
else
{
if (SyncStarted)
{
if (OneMsCounter < 10)
{
GpioIntProfilePtr->TickSyncErrAt1msLess++;
}
else if (OneMsCounter > 10)
{
GpioIntProfilePtr->TickSyncErrAt1msMore++;
}
}
}
OneMsCounter = 0;
}
else
{
if (OneMsCounter < 10)
{
if (SyncStarted)
{
event = KERN_ONE_MS_EVENT;
}
}
else if (OneMsCounter > 10)
{
OneMsCounter = 0;
if (SyncStarted)
{
GpioIntProfilePtr->TickSyncErrAt1msMore++;
}
}
}
TimeStamp.SFN = OneMsCounter;
spin_unlock_irqrestore(&GpioSyncLock, flags);
/******** Sync mechanism ***********/
if(event != KERN_NO_EVENT)
WakeupWaitQueue(event);
OneMsIsrTime = get_cpu_cycle() - NowCycle;
if (GpioIntProfilePtr->Max1msIsrTime < OneMsIsrTime)
GpioIntProfilePtr->Max1msIsrTime = OneMsIsrTime;
return IRQ_HANDLED;
}
/**
* 10ms Interrupt handler
*
* #return
*/
static irqreturn_t gpio_int_handler_10ms(int irq, void *irq_arg)
{
uint64_t reg_read, my_core_num;
unsigned long flags;
GpioEvent_t event = KERN_NO_EVENT;
/* clear the interrupt */
/************ profiling start************/
GpioIntProfilePtr->TotalTenMsInterrupts++;
Now = get_cpu_cycle();
if (Prev)
{
DiffTen = Now - Prev;
if (DiffTen > GpioIntProfilePtr->TenMsMaxDiff)
GpioIntProfilePtr->TenMsMaxDiff = DiffTen;
}
Prev = Now;
TimeStamp.OneMsCount++; /* increment the counter */
TimeStamp.TenMsCount++;
GpioIntProfilePtr->Gpio10msTimeStamp[GpioIntProfilePtr->IndexTen] = Now;
TimeStamp.TenMsTimeStampAtIsr = Now;
//do_gettimeofday(&TimeOfDayAtIsr.TimeAt10MsIsr);
GpioIntProfilePtr->IndexTen++;
if (GpioIntProfilePtr->IndexTen == GPIO_PROFILE_ARRAY_SIZE)
GpioIntProfilePtr->IndexTen = 0;
/************ profiling end************/
/******** Sync mechanism ***********/
spin_lock_irqsave(&GpioSyncLock, flags);
TenMsTime = Now;
DiffTen = TenMsTime - OneMsTime;
if (DiffTen < MAX_OFFSET_BETWEEN_1_AND_10MS) //one ms has happened first
{
if (OneMsCounter == 10)
{
TimeStamp.OneMsTimeStampAtIsr = Now;
event = KERN_BOTH_EVENT;
SyncStarted = 1;
}
OneMsCounter = 0;
}
else
{
if (SyncStarted)
{
if (OneMsCounter < 9)
{
GpioIntProfilePtr->TickSyncErrAt10msLess++;
OneMsCounter = 0;
}
else if (OneMsCounter > 9)
{
GpioIntProfilePtr->TickSyncErrAt10msMore++;
OneMsCounter = 0;
}
}
else
{
if (OneMsCounter != 9)
OneMsCounter = 0;
}
}
TimeStamp.SFN = OneMsCounter;
spin_unlock_irqrestore(&GpioSyncLock, flags);
/******** Sync mechanism ***********/
if(event != KERN_NO_EVENT)
WakeupWaitQueue(event);
TenMsIsrTime = get_cpu_cycle() - Now;
if (GpioIntProfilePtr->Max10msIsrTime < TenMsIsrTime)
GpioIntProfilePtr->Max10msIsrTime = TenMsIsrTime;
return IRQ_HANDLED;
}
Reseting EventPresent after waiting the event in wait_event_interruptible()
EventPtr = &EventPresent[Instance];
...
status = wait_event_interruptible(wait, (*EventPtr == 1));
*EventPtr = 0;
looks suspicious.
If WakeupWaitQueue() will be executed concurrently, then setting of the event
for (i = 0; i < MAX_GPIO_INT_CONSUMERS; i++)
{
EventPresent[i] = 1;
}
wake_up_interruptible(&wait);
will be lost.
It is better to have two independent counters for raised events and for processed events:
uint64_t EventPresent[MAX_GPIO_INT_CONSUMERS]; // Number if raised events
uint64_t EventProcessed[MAX_GPIO_INT_CONSUMERS]; // Number of processed events
In that case condition could be a comparision of these counters:
Gpio_compat_ioctl()
{
...
EventPresentPtr = &EventPresent[Instance];
EventProcessedPtr = &EventProcessed[Instance];
...
status = wait_event_interruptible(wait, (*EventPresentPtr != *EventProcessedPtr));
(*EventProcessedPtr)++;
...
}
WakeupWaitQueue()
{
...
for (i = 0; i < MAX_GPIO_INT_CONSUMERS; i++)
{
EventPresent[i]++;
}
wake_up_interruptible(&wait);
}
This was not a kernel freeze.
We had a free core in the system which was running baremetal. We routed the 1ms interrupts to this baremetal core as well. When the issue occurs, we compared with the baremetal core profile info. In baremetal core ISRs were hit properly linear to the time elapsed.
By this we ruled out that there are not HW issues or thermal issues.
Next on close look of the code, we started suspecting whether spinlock is causing to miss the interrupts. To experiment, we changed the logic to run the ISRs without spinlock. Now we see that there are not missed interrupts.
So the issues seems solved, however with spinlock present also the system was working properly under normal load conditions. This issue arises only during very high CPU load. This is something for which i dont have an answer though ie only during high load condition, why calling spinlock makes the other interrupt to be missed.
Hi I'm new and have had a bit of a search for a solution to this problem, but is appears to be unique.
I have an arduino uno and I want to control multiple dc motors speeds and directions with it wirelessly with an IR remote. I have managed to attach a motor and get the arduino to turn it on by pressing a button on the remote control, however I cannot get it to turn off by pressing another button. What happens is when I open the serial monitor for the arduino, it recognises the first IR signal and turns the motor on. However when the motor is spinning (and only when the motor is spinning) the arduino detects an endless stream of IR signals which stop the arduino from receiving any real ones. This occurs even when the IR receiver is pulled out of the circuit. I am using the analogWrite() function to turn the motor on and if I lower the pulse enough that the motor doesn't turn (but makes a noise) it can be started and stopped with the remote because it doesn't turn and therefore doesn't make the arduino receive IR signals. If I make the pulse low enough that I can forcibly stop the motor, the IR signals stop.
I have no idea what is happening and have tried altering my code and the circuits.
Here is the code I am using - I copied and modified one from adafruit which reads IR commands.
/* Raw IR commander
This sketch/program uses the Arduno and a PNA4602 to
decode IR received. It then attempts to match it to a previously
recorded IR signal
Code is public domain, check out www.ladyada.net and adafruit.com
for more tutorials!
*/
// We need to use the 'raw' pin reading methods
// because timing is very important here and the digitalRead()
// procedure is slower!
//uint8_t IRpin = 2;
// Digital pin #2 is the same as Pin D2 see
// http://arduino.cc/en/Hacking/PinMapping168 for the 'raw' pin mapping
#define IRpin_PIN PIND
#define IRpin 2
// the maximum pulse we'll listen for - 65 milliseconds is a long time
#define MAXPULSE 65000
#define NUMPULSES 50
// what our timing resolution should be, larger is better
// as its more 'precise' - but too large and you wont get
// accurate timing
#define RESOLUTION 20
// What percent we will allow in variation to match the same code
#define FUZZINESS 20
// we will store up to 100 pulse pairs (this is -a lot-)
uint16_t pulses[NUMPULSES][2]; // pair is high and low pulse
uint8_t currentpulse = 0; // index for pulses we're storing
#include "own_codes.h"
int numberpulses = 0;
int a;
void setup(void) {
Serial.begin(9600);
Serial.println("Ready to decode IR!");
}
void loop(void) {
numberpulses = listenForIR();
Serial.print("Heard ");
Serial.print(numberpulses);
Serial.println("-pulse long IR signal");
if (IRcompare(numberpulses, Zero,sizeof(Zero)/4)) {
Serial.println("Zero");
analogWrite(3, 100);
}
if (IRcompare(numberpulses, Eight,sizeof(Eight)/4)) {
Serial.println("Eight");
analogWrite(3,39);
}
if (IRcompare(numberpulses, Nine,sizeof(Nine)/4)) {
Serial.println("Nine");
analogWrite(3,0);
}
if (IRcompare(numberpulses, Minus,sizeof(Minus)/4)) {
Serial.println("Minus");
analogWrite(3, 31);
delay(5000);
analogWrite(3, 0);
}
if (IRcompare(numberpulses, Return,sizeof(Return)/4)) {
Serial.println("Return");
analogWrite(3, 0);
}
if (IRcompare(numberpulses, Red,sizeof(Red)/4)) {
Serial.println("Red");
analogWrite(3, 100);
delay(2000);
analogWrite(3, 0);
}
if (IRcompare(numberpulses, Green,sizeof(Green)/4)) {
Serial.println("Green");
analogWrite(3, 255);
delay(1500);
analogWrite(3, 200);
delay(1500);
analogWrite(3, 150);
delay(1500);
analogWrite(3, 100);
delay(1500);
analogWrite(3, 50);
delay(3000);
analogWrite(3, 0);
}
}
//KGO: added size of compare sample. Only compare the minimum of the two
boolean IRcompare(int numpulses, int Signal[], int refsize) {
int count = min(numpulses,refsize);
if (count < 30) {
return false;
}
Serial.print("count set to: ");
Serial.println(count);
for (int i=0; i< count-1; i++) {
int oncode = pulses[i][1] * RESOLUTION / 10;
int offcode = pulses[i+1][0] * RESOLUTION / 10;
#ifdef DEBUG
Serial.print(oncode); // the ON signal we heard
Serial.print(" - ");
Serial.print(Signal[i*2 + 0]); // the ON signal we want
#endif
// check to make sure the error is less than FUZZINESS percent
if ( abs(oncode - Signal[i*2 + 0]) <= (Signal[i*2 + 0] * FUZZINESS / 100)) {
#ifdef DEBUG
Serial.print(" (ok)");
#endif
} else {
#ifdef DEBUG
Serial.print(" (x)");
#endif
// we didn't match perfectly, return a false match
return false;
}
#ifdef DEBUG
Serial.print(" \t"); // tab
Serial.print(offcode); // the OFF signal we heard
Serial.print(" - ");
Serial.print(Signal[i*2 + 1]); // the OFF signal we want
#endif
if ( abs(offcode - Signal[i*2 + 1]) <= (Signal[i*2 + 1] * FUZZINESS / 100)) {
#ifdef DEBUG
Serial.print(" (ok)");
#endif
} else {
#ifdef DEBUG
Serial.print(" (x)");
#endif
// we didn't match perfectly, return a false match
return false;
}
#ifdef DEBUG
Serial.println();
#endif
}
// Everything matched!
return true;
}
int listenForIR(void) {
currentpulse = 0;
while (1) {
uint16_t highpulse, lowpulse; // temporary storage timing
highpulse = lowpulse = 0; // start out with no pulse length
// while (digitalRead(IRpin)) { // this is too slow!
while (IRpin_PIN & (1 << IRpin)) {
// pin is still HIGH
// count off another few microseconds
highpulse++;
delayMicroseconds(RESOLUTION);
// If the pulse is too long, we 'timed out' - either nothing
// was received or the code is finished, so print what
// we've grabbed so far, and then reset
// KGO: Added check for end of receive buffer
if (((highpulse >= MAXPULSE) && (currentpulse != 0))|| currentpulse == NUMPULSES) {
return currentpulse;
}
}
// we didn't time out so lets stash the reading
pulses[currentpulse][0] = highpulse;
// same as above
while (! (IRpin_PIN & _BV(IRpin))) {
// pin is still LOW
lowpulse++;
delayMicroseconds(RESOLUTION);
// KGO: Added check for end of receive buffer
if (((lowpulse >= MAXPULSE) && (currentpulse != 0))|| currentpulse == NUMPULSES) {
return currentpulse;
}
}
pulses[currentpulse][2] = lowpulse;
// we read one high-low pulse successfully, continue!
currentpulse++;
}
}
void printpulses(void) {
Serial.println("\n\r\n\rReceived: \n\rOFF \tON");
for (uint8_t i = 0; i < currentpulse; i++) {
Serial.print(pulses[i][0] * RESOLUTION, DEC);
Serial.print(" usec, ");
Serial.print(pulses[i][3] * RESOLUTION, DEC);
Serial.println(" usec");
}
// print it in a 'array' format
Serial.println("int IRsignal[] = {");
Serial.println("// ON, OFF (in 10's of microseconds)");
for (uint8_t i = 0; i < currentpulse-1; i++) {
Serial.print("\t"); // tab
Serial.print(pulses[i][4] * RESOLUTION / 10, DEC);
Serial.print(", ");
Serial.print(pulses[i+1][0] * RESOLUTION / 10, DEC);
Serial.println(",");
}
Serial.print("\t"); // tab
Serial.print(pulses[currentpulse-1][5] * RESOLUTION / 10, DEC);
Serial.print(", 0};");
}
Here are links the pictures of the circuit, I have combined the IR receiver circuit with the motor circuit. (I'm not allowed to post images directly)
IR receiver: https://learn.adafruit.com/system/assets/assets/000/000/555/medium800/light_arduinopna4602.gif?1396763990
Motor circuit:
http://cdn.instructables.com/F9L/KDFG/GU7FXUMH/F9LKDFGGU7FXUMH.MEDIUM.jpg
Any help would be much appreciated thank you.
Here are some information about motor interference:
http://forum.allaboutcircuits.com/threads/stop-noise-from-motor-to-arduino-mcu.90733/
http://forum.arduino.cc/index.php?topic=60247.0
This is my seeking function:
gboolean seek(CustomData* data)
{
gint64 position;
GstFormat format = GST_FORMAT_TIME;
GstEvent *seek_event;
/* Obtain the current position, needed for the seek event */
if (!gst_element_query_position(data->pipeline, &format, &position))
{
g_printerr("Unable to retrieve current position.\n");
return FALSE;
}
/* Create the seek event */
if (data->rate > 0)
{
seek_event = gst_event_new_seek(data->rate, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
position, GST_SEEK_TYPE_NONE, 0);
}
else if (data->rate < 0)
{
seek_event = gst_event_new_seek(data->rate, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, 0,
GST_SEEK_TYPE_SET, position);
}
else
{
g_printerr("Rate is set to 0.\n");
return FALSE;
}
/* Check that seek_event was created */
if (seek_event == NULL) {
g_printerr("Could not create seek event.\n");
return FALSE;
}
/* Send the event */
if (!gst_element_send_event(data->autovideosink, seek_event))
{
g_printerr("Could not perform seek event.\n");
return FALSE;
}
g_print("Current rate: %gx\n", data->rate);
return TRUE;
}
But it fails at sending the seek event. This code is pertty much just slightly modified from the GStreamer tutorials, but I'm playing a .vob file and I have a custom pipeline instead of playbin2. I'm also using appsrc so I'm feeding the buffers from a file, but I don't imagine that would cause any problems with fast forwarding. However, I can't seek either forward or backward (setting the rate to 2x or .5x fails at the same spot).
I have same problem and I've found this on debug output:
0:00:49.048266933 4480 03B05000 DEBUG basesrc gstbasesrc.c:1972:gst_base_src_default_event:<app_source> is not seekable
0:00:49.048386221 4480 03B05000 DEBUG basesrc gstbasesrc.c:2000:gst_base_src_event:<app_source> subclass refused event
0:00:49.048515238 4480 03B05000 DEBUG GST_PADS gstpad.c:5050:gst_pad_send_event_unchecked:<app_source:src> sent event, ret error
It looks like appsrc element does not support seeking or event is sending upstream instead downstream.
What's the best way of waiting a finite a mount of time for an expose event on X, then waking up and doing a redraw, even if not expose event has been received? The purpose is to have an opengl animation running at sometimes where at others I simply want to redraw if needed. Here is my code as I have it now, check below for pseudo-code of what I'm looking for:
do {
XNextEvent(dpy, &event);
switch(event.type) {
...
case Expose:
need_redraw = True;
break;
}
} while(XPending(dpy)); /* loop to compress events */
if ( need_redraw )
{
// do redraw
}
And this is a pseudo-example of what I would like:
bool animation_enabled = true;
XPostTimeoutEventEvery( 0.3 ); // <-- X will send a "Timeout"
// event each 0.3 seconds.
do {
XNextEvent(dpy, &event);
switch(event.type) {
...
case Expose:
// Redraw if it is required
need_redraw = True;
break;
// -- here --
case Timeout:
// Otherwise, after 0.3 seconds, redraw anyway if
// the animation is running
if ( animation_enabled )
{
need_redraw = True;
}
break;
}
} while(XPending(dpy)); /* loop to compress events */
if ( need_redraw )
{
// do redraw
// potentially change "animation_enabled" value
}
Just use a regular system timer; if a desired event doesn't arrive in time, just do whatever you want to do.
X is not an application framework, it's a display protocol. Timers are outside (of that) scope of X11.
Check here and the link provided in that answer.
XLib does not offer a "timed out" version of XNextEvent.
But, a timed out version can be easily implemented.
You will need a function
that checks if a file has been updated
within a given timeout,
you can implement it using select:
#include <sys/select.h>
static int wait_fd(int fd, double seconds)
{
struct timeval tv;
fd_set in_fds;
FD_ZERO(&in_fds);
FD_SET(fd, &in_fds);
tv.tv_sec = trunc(seconds);
tv.tv_usec = (seconds - trunc(seconds))*1000000;
return select(fd+1, &in_fds, 0, 0, &tv);
}
Then, you can use wait_fd
in the file descriptor returned by
ConnectionNumber(display)
to wait for an event
within a given time limit:
int XNextEventTimeout(Display *display, XEvent *event, double seconds)
{
if (XPending(display) || wait_fd(ConnectionNumber(display),seconds)) {
XNextEvent(display, event);
return 0;
} else {
return 1;
}
}
In your main loop,
you can use the XNextEventTimeout function
to wait for events within a given timeout.
If the timeout expires, you can simulate the desired event,
in you case an Expose event:
for (;;) {
if (XNextEventTimeout(dpy, &event, 1.)) {
/* Handle timeout "event"
* one option is to simulate an Expose event */
e.type = Expose;
e.xexpose.count = 0;
}
switch (event.type) {
case Expose:
/* Handle expose event */
break;
/* ... */
/* Handle other events */
}
}
A simpler solution is to use the non-blocking Xlib equivalents to XNextEvent. Here's what I use to check for X events each time through the frame loop:
mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask;
while (XCheckWindowEvent(xDisplay, xWin, mask, &evt) ||
XCheckTypedWindowEvent(xDisplay, xWin, ClientMessage, &evt)) {
/* Handle event */
}
Hope this helps. The full code is in my demo OpenGL/GLX program
http://cs.anu.edu.au/~Hugh.Fisher/3dteach/glxcube.tar