I've scheduled HIDManager on main thread (runLoop) using IOHIDManagerScheduleWithRunLoop.
So, I get the device matching & removal callbacks on main thread.
But, I've scheduled a device IOHIDDeviceScheduleWithRunLoop on a different thread, Say Thread-1. According to the documentation it, When I set a report, I should receive a callback on the Thread-1 RunLoop.
IOHIDDeviceScheduleWithRunLoop( inIOHIDDeviceRef, CFRunLoopGetCurrent( ), kCFRunLoopDefaultMode );
But, I am recieving the HIDReport callback on the main thread.
Any help ?
UPDATE:
I see the report callback is getting called even If I removed IOHIDDeviceScheduleWithRunLoop. The report callback supposed to be called on the device RunLoop.
According to the documentation of IOHIDManagerScheduleWithRunLoop , "This formally associates the HID Manager with the client's run loop. This schedule will propagate to all HID devices that are currently enumerated and to new HID devices as they are matched by the HID Manager"
This should be used only for matching and removal, But I am getting for input reports too.
Do you have a runloop on thread-1? If it is a command line app, you have to explicitly start a run loop (by calling for instance CFRunLoopRun())
Related
I'm currently trying to use Rust C interop in order to send actional desktop notifications (using a modified version of this lib). The main goal here would be to handle these notification sending events on separate threads like so:
thread::spawn(move || unsafe {
sys::sendNotification(
NSString::from_str(&title).deref(),
NSString::from_str(&message).deref(),
NSString::from_str(&uri).deref(),
NSString::from_str(&img.unwrap_or_default()).deref(),
);
});
This would allow me to have multiple notification 'handlers' running at the same time (vs. just being able to have a single notification displayed at once), and would also allow my main process to run without being blocked. Given the nature of the program (web-scraper), I don't want scraping halted whenever a notification is being displayed.
That said, this approach is somewhat problematic because the underlying obj-c code relies on NSRunLoop to handle click events (e.g., user clicks on the action to open a web page) through the created NotificationCenterDelegate instance. Per my knowledge (feel free to fact-check me on this I'm not familiar with obj-c), NSRunLoops only operate on the main thread and this code is rendered useless if ran on a worker... The notification still sends in this scenario, but events aren't processed.
Is there a way to handle this that is more effective than running my scraping logic on a separate loop and sending notif-send events to the main thread for processing (which will probably be halted by a notification that I hadn't opened)?
Strictly speaking, there is (or can be) one NSRunLoop per thread, not only the main thread. But it's still the case that GUI stuff generally needs to run on the main thread.
I recommend that you take the approach of running scraping on a separate thread. This is generally a good idea for any combination of long-running work and GUI — it ensures that the work cannot cause the UI to hang or hiccup.
I am trying to integrate OpenThread child with an existing application on the TI CC2652R1 and am having issues trying to join/create a Thread network. Currently I have an external event that calls a function to join and start OpenThread. Below is a snip of this function relating to the join:
bool is_commissioned = otDatasetIsCommissioned(OtStack_instance);
otJoinerState joiner_state = otJoinerGetState(OtStack_instance);
if(!is_commissioned && (OT_JOINER_STATE_IDLE == joiner_state)){
otError error = otIp6SetEnabled(OtStack_instance, true);
error = otThreadSetEnabled(OtStack_instance, true);
error = otJoinerStart(OtStack_instance, "PSK", NULL, "Company", "Device", "0.0.0", NULL, joiner_callback, NULL);
}
otJoinerStart never seems to resolve because joiner callback never is called and additional calls to my joining function show that the joiner state is OT_JOINER_STATE_DISCOVER and the OpenThread instance says that it is initialized. Is there a way to set the joiner callback timeout? I have looked through the documentation and could not find out how the join timeout is set.
Thanks
Joining a Thread device to a Thread network assumes that you have a Thread network running and there is an active commissioner with the joiner's EUI64 and PSK. Make sure that these are setup before you try and call this function to join. It is also helpful to have a sniffer running on the Thread network's channel to ensure the commissioner or joiner router is responding properly.
Joining in Thread is done with an active scan on all the available channels in the IEEE 802.15.4 page 0. The time to send a Joiner request and the time the joiner waits on each channel is not immediately configurable. However these active scans usually complete within a few seconds. Your joiner callback should be getting called with a join failed condition if there are no available joiner routers in about 5 seconds.
The examples in the OpenThread github repository are written in a nortos fashion. Any application code is run in a tasklet and the main loop only calls two functions; process tasklets and process drivers. In the TI SDK we use TI-RTOS and you seem to have based your code on these examples. In general the OtStack_Task will handle processing of OpenThread and the platform driver interface; but deadlocks in a multi-threaded system can occur.
You can use ROV in CCS or IAR to check the state of the kernel and RTOS objects. In CCS with an active debug session, select; Tools >> Runtime Object View. Then check if the stack task is blocking on the API semaphore. Or if the application task is hogging up the processor. This can be due to an unpaired lock/unlock on the API semaphore, or the application task may be in a busy wait.
Immediately I don't see anything wrong with the code snippet posted.
I've got a strange problem using CoreBluetooth on Mac mini. By design, my code should receive a data update notification after discovering a characteristics service once it's connected. The problem is no data will be updated if a event is triggered by hardware within very first 20 seconds.
I've test the same code in the iOS,but it all works fine without any dealy. So the question is:
Does Apple delay the -[didUpdateValueForCharacteristic:] notification after first BLE connection?
In addition, I am using a custom profile ( A self defined UUID).
Thanks.
According to documentation:
This method is invoked when your app calls the
readValueForCharacteristic: method, or when the peripheral notifies
your app that the value of the characteristic for which notifications
and indications are enabled (via a successful call to
setNotifyValue:forCharacteristic:) has changed.
So no, it's not guaranteed that this method will be called after discovering a characteristic. You either have to call readValueForCharacteristic or subscribe to notifications and wait until peripheral sends a notification.
However, after discovering a characteristic, you can get its value in peripheral:didDiscoverCharacteristicsForService:error: method.
As my first Mac application, I'm building an app that displays incoming MIDI timecode.
Therefore, I am having an instance of the RtMidi "library" which wraps the MIDI in and out stuff.
The Mac OS Core MIDI callback is in blank C and is called on multiple threads internally. The RtMidi stuff in in C++ and forwards this multi-threaded call to one single (the main) thread.
As I need a Cocoa function to notify other classes that a new MIDI timecode has arrived ( which happens about every 7-9 ms ), I implemented a Singleton which all necessary classes observe.
So, the order in which the functions are called is :
Core MIDI callback -> RtMidi function -> user callback -> Notification ( via Singleton )
Basically, this works!
The problem is that I right now have everything on the same thread ( the main thread). If I post a notification from the MIDI callback and the called functions take longer to complete than the above mentioned 7-9 ms, the Core MIDI callback gets blocked which causes the whole application to freeze.
I tried debugging and it seems that there is some kind of deadlock occurring.
Anyone has some directions on how to implement multithreading in this case?
As I also do UI updating in the notification observers, I would need all notifications to appear on the main thread. What I don't understand is how everything goes with C / C++ / Objective-C in this particular case.
I would suggest that at the stage that you forward your call from your background thread to the main thread that you do so in a non-blocking manner, if possible. For example, you could use performSelectorOnMainThread:withObject:waitUntilDone:, passing NO for the last argument, or some other mechanism like dispatch_async(dispatch_get_main_queue(), ^{ ... }). This will prevent your background thread from getting blocked, and allow the UI to be updated whenever it has time to do so.
in my Cocoa project, I communicate with a device connected to a serial port. Now, I am waiting for the serial device to send a particular message of some bytes. For the read operation (and the reaction for once the desired message has been received), I created a new thread. On user request, I want to be able to cancel the thread.
As Apple suggests in the docs, I added a flag to the thread dictionary, periodically check if the flag has been set and if so, call [NSThread exit]. This works fine.
Now, the thread may be stuck waiting for the serial device to finally send the 12 byte message. The read call looks like this:
numBytes = read(fileDescriptor, buffer, 12);
Once the thread starts reading from the device, but no data comes in, I can set the flag to tell the thread to finish, but the thread is not going to read the flag unless it finally received at least 12 bytes of data and continues processing.
Is there a way to kill a thread that currently performs a read operation on a serial device?
Edit for clarification:
I do not insist in creating a separate thread for the I/O operations with the serial device. If there is a way to encapsulate the operations such that I am able to "kill" them if the user presses a cancel button, I am perfectly happy.
I am developing a Cocoa application for desktop Mac OS X, so no restrictions regarding mobile devices and their capabilities apply.
A workaround would be to make the read function return immediately if there are no bytes to read. How can I do this?
Use select or poll with a timeout to detect when the descriptor is ready for reading.
Set the timeout to (say) half a second and call it in a loop while checking to see if your thread should exit.
Asynchronous thread cancellation is almost always a bad idea. Try to stick with event-driven interfaces (and, if necessary, timeouts).
This is exactly what the pthread_cancel interface was designed for. You'll want to wrap the block with read in pthread_cleanup_push and pthread_cleanup_pop in order that you can safely clean up if the thread is cancelled, and also disable cancellation (with pthread_setcancelstate) in other code that runs in this thread that you don't want to be cancellable. This can be a pain if proper cleanup would involve multiple call frames; it essentially forces you to use pthread_cleanup_push at every call level and structure your thread code like C++ or Java with try/catch style exception handling.
An alternative approach would be to install a signal handler for an otherwise-unused signal (like SIGUSR1 or one of the realtime signals) without the SA_RESTART flag, so that it interrupts syscalls with EINTR. The signal handler itself can be a complete no-op; the only purpose of it is to interrupt things. Then you can use pthread_kill to interrupt the read (or any other syscall) in a particular thread. This has the advantage that you don't have to switch your code to using C++/Java-type idioms. You can handle the EINTR error by checking a flag (indicating whether the thread was requested to abort) and resume the read if the flag is not set, or return an error code that causes the caller to clean up and eventually pthread_exit.
If you do use interrupting signal handlers, make sure all your syscalls that can return EINTR are wrapped in loops that retry (or check the abort flag and optionally retry) on EINTR. Otherwise things can break badly.