My Run Loop Observer is written as follows:
void observerCallback(CFRunLoopObserverRef observer,
CFRunLoopActivity activity, void* info)
{
println("%u", activity);
}
//-----------------------------
void InstallObserver()
{
CFRunLoopObserverRef myObserver = NULL;
int myActivities = kCFRunLoopEntry;
myObserver = CFRunLoopObserverCreate(NULL, myActivities, YES,
/* repeat */ 0, &observerCallback, NULL);
if (myObserver)
{
CFRunLoopAddObserver(CFRunLoopGetCurrent(), myObserver,
kCFRunLoopCommonModes);
}
}
Every time I press any key in my Application the observerCallback is called 4 times.
The question is:
How can I obtain key code inside observerCallback?
Thanks.
Based on the comments on your question, you want a local event monitor, AKA:
+[NSEvent addLocalMonitorForEventsMatchingMask:handler:]
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSEvent_Class/Reference/Reference.html#//apple_ref/occ/clm/NSEvent/addLocalMonitorForEventsMatchingMask:handler:
Related
I'm trying to use encoders to track the movement of three wheels on a robot, but as soon as any of the motors move the robot "locks up", it stops responding to commands, stops printing to the serial monitor, and just keeps spinning its wheels until I turn it off. I cut out everything except just the code to track one encoder and tried turning the wheel by hand to sus out the problem, but it still locked up. And even more strangely, now it will start spinning one of the wheels even though I've removed any code that should have it do that, even by mistake.
I used the Arduino IDE to program the pico since I've got no familiarity with python, but I can't find any information or troubleshooting tips for using interrupts with the pico that don't assume you're using micropython.
Here's the simplified code I'm using to try to find the problem. All it's meant to do is keep track of how many steps the encoder has made and print that to the serial monitor every second. Ive tried removing the serial and having it light up LEDs instead but that didn't help.
int encA = 10;
int encB = 11;
int count = 0;
int timer = 0;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
attachInterrupt(digitalPinToInterrupt(encA),readEncoder,RISING);
timer = millis();
}
void loop() {
// put your main code here, to run repeatedly:
if (timer - millis() > 5000) {
Serial.println(count);
timer = millis();
}
}
void readEncoder() {
int bVal = digitalRead(encB);
if (bVal == 0) {
count--;
}
else{
count++;
}
}
Does the mapping function digitalPinToInterrupt for the Pi Pico work?
Can you try just using the interrupt number that corresponds to the pi?
attachInterrupt(9,readEncoder,RISING); //Or the number 0-25 which maps to that pin
https://raspberrypi.github.io/pico-sdk-doxygen/group__hardware__irq.html
You have the wrong pin to encoder in your example (maybe you incorrectly copy and pasted)?
attachInterrupt(digitalPinToInterrupt(**encA**),readEncoder,RISING);
void readEncoder() {
int bVal = digitalRead(**encB**); ...}
There is similar code on GitHub that you could modify and try instead.
https://github.com/jumejume1/Arduino/blob/master/ROTARY_ENCODER/ROTARY_ENCODER.ino
It might help you find a solution.
Also,
https://www.arduino.cc/reference/en/libraries/rpi_pico_timerinterrupt/
The interrupt number corresponds to the pin (unless you have reassigned it or disabled it) so for pin 11 the code can be:
attachInterrupt(11, buttonPressed, RISING);
This works:
bool buttonPress = false;
unsigned long buttonTime = 0; // To prevent debounce
void setup() {
Serial.begin(9600);
pinMode(11, INPUT_PULLUP);
attachInterrupt(11, buttonPressed, RISING);
// can be CHANGE or LOW or RISING or FALLING or HIGH
}
void loop() {
if(buttonPress) {
Serial.println(F("Pressed"));
buttonPress= false;
} else {
Serial.println(F("Normal"));
}
delay(250);
}
void buttonPressed() {
//Set timer to work for your loop code time
if (millis() - buttonTime > 250) {
//button press ok
buttonPress= true;
}
buttonTime = millis();
}
See: https://raspberrypi.github.io/pico-sdk-doxygen/group__hardware__irq.html for disable, enable etc.
I am blinking LED using TIM2 General timer.
Code in main.c
HAL_TIM_Base_Start_IT(&htim2);
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
if(htim->Instance==TIM2){
HAL_GPIO_TogglePin(GPIOB, LED_Pin);
}
}
When the button is clicked EXTI interrupt should be called to blink the led faster 20 times. However, LED stays on and stops blinking at all.
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
if(GPIO_Pin == BT_Pin){
for(volatile int i=20; i>0; i--){
HAL_GPIO_TogglePin(GPIOB, LED_Pin);
HAL_Delay(100);
}
}
}
Could you please advice how can i adjust interrupt ISR for EXTI so it will use TIM2 as well with faster blinking.
HAL_GPIO_EXTI_Callback() runs in the interrupt context - it is not appropriate to flash the indicator there much less include a delay. No other code while run while in the interrupt, and HAL_Delay() is probably not interrupt safe in any case.
Instead, in the button handler, set a down-counter to be decremented in the timer handler, and in the timer handler set the reload depending on the down-counter being zero or not. Something like this:
[I have not included the HAL calls to do the TODO's above, because I'd have to look them up, but that is the outline.]
volatile unsigned fast_flash_count = 0 ;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM2)
{
HAL_GPIO_TogglePin(GPIOB, LED_Pin);
if( fast_flash_count > 0 )
{
fast_flash_count-- ;
// Set TIM2 reload to fast-flash period
TODO
}
else
{
// Set TIM2 reload to slow-flash period
TODO
}
}
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == BT_Pin)
{
fast_flash_count = 20 ;
// Set TIM2 counter to current reload value
// to force immediate interrupt
TODO
}
}
I am writing a GUI for a small monochromatic display and I want to update the data on the screen every second.
The data is stored in a redis database and I am trying to coordinate using pthread, libev, and asynchronous hiredis calls.
My plan is to have a thread that pulls new data from the database every second and store a local copy for quick access.
Another thread that updates the screen will access that data at will without having to wait for database access.
First question, is my approach correct?
Second question, why am I having trouble polling the database every second? I think I can switch to a synchronous method and get it to work but is that the right approach?
Here is the relevant code:
int main(int argc, char *argv[])
{
pthread_t dataThread;
pthread_t guiThread;
pthread_create(&dataThread, NULL, dataHandler, NULL);
pthread_create(&guiThread, NULL, guiHandler, NULL);
while (true)
{
sleep(10);
}
return 0;
}
In the following, if I move ev_loop(EV_DEFAULT_ 0); inside the while loop after the redisAsync commands my callback gets called for the first loop but never again. The way it sits, my callback never gets called.
void* dataHandler(void *ptr)
{
m_ctx = redisAsyncConnect("127.0.0.1", 6379);
if (m_ctx->err) {
printf("Redis async connection failed. Error: %s\n", m_ctx->errstr);
exit(-1);
}
redisLibevAttach(EV_DEFAULT_ m_ctx);
redisAsyncSetConnectCallback(m_ctx,connectCallback);
redisAsyncSetDisconnectCallback(m_ctx,disconnectCallback);
ev_loop(EV_DEFAULT_ 0);
while (true)
{
int result;
result = redisAsyncCommand(m_ctx, updateCallback, (char*)"data1", "HGET data1 data");
printf("result: %d\n", result);
result = redisAsyncCommand(m_ctx, updateCallback, (char*)"data2", "HGET data2 data");
printf("result: %d\n", result);
//ev_loop(EV_DEFAULT_ 0); <- this will work one time
}
redisAsyncDisconnect(m_ctx);
return 0;
}
void updateCallback(redisAsyncContext *c, void *r, void *privdata)
{
redisReply *reply = (redisReply*)r;
if (reply == NULL) return;
printf("%s: %s\n", (char*)privdata, reply->str);
}
void* guiHandler(void *ptr)
{
while (true)
{
// Update the GUI accordingly
sleep(1);
}
}
Firstly, I would recommend you to read the manual for libev before using it :
http://man7.org/linux/man-pages/man3/event.3.html
Now for your code,
ev_loop function will start an event loop that you only "feed" it with 2 HGET operations.
In order to add more operations you need to add attach events for the event loop but I'm not sure it will be the right approach for you case.
If the purpose of your thread is just to fetch the db every X seconds why are you using the async approach at all? IMO just use the hiredis sync API
My app's memory usage goes up permanently, each time I create a keyboard event using Quartz Event Services.
The following is the problematic code inside of an infinite loop:
int keyCode = 0;
BOOL keyDownBool = FALSE;
while (TRUE) {
/* creating a keyboard event */
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStatePrivate);
CGEventRef keyboardEvent =
CGEventCreateKeyboardEvent(source, (CGKeyCode)keyCode, keyDownBool);
CFRelease(source);
CFRelease(keyboardEvent);
}
Instruments.app says that there are no memory leaks...
What is the problem here?
Thank you for your help!
Okay so the solution is pretty simple. You only need to create your CGEventSourceRef once, and then you can reuse it each time you want to post an event. Creating your CGEventSourceRefover and over again causes the "leaks" to happen.
The proper code looks like this:
int keyCode = 0;
BOOL keyDownBool = FALSE;
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStatePrivate);
while (TRUE) {
/* creating a keyboard event */
CGEventRef keyEvent =
CGEventCreateKeyboardEvent(source, (CGKeyCode)keyCode, keyDownBool);
CFRelease(keyEvent);
}
Thanks to #Willeke for the suggestion.
I've pored through most of the posts regarding the creation of Global Hotkeys using Carbon. Is it possible in the hot key handler function to return eventNotHandledErr and have the event passed on to the next handler? Here's some pseudocode:
OSStatus myHotKeyHandler(EventHandlerCallRef nextHandler, EventRef anEvent, void *userData)
{
OSStatus result;
if ( appX is running || appY is running ) {
[(MyAppController *) userData doSomething];
result = noErr;
} else {
result = eventNotHandledErr;
}
return result;
}
In the event that I'm not in application X or Y, I want to be able to pass the event on. Is this possible?
I know I can set up a notification for application switched events, but that requires Enable access for assistive devices to be turned on. If there's a way to pass the event to the next handler, that would be great.