Is there a user timer lib like the software Timers on Photon or the SparkInterval available? I want to use the low frequency clock and fire interrupts to call functions (or set flags if ISR like) instead of using the ol’ if (millis > whatever) stuff.
It’s on the list! Shouldn’t be too hard to add once I get a few spare cycles
@eric, I have to look into the timer resources on the nrRF51. I could adapt my SparkIntervalTimer library to make use of available timers.
From what I’ve read the way to go is to use app timers which sit on top of RTC used by soft device. Looks fairly approachable and should help people keep stuff out the loop which appears to be best?
Sounds like I need to do some reading on the nRF51 core libs!
Yes, we use app timers internally for the system firmware. It would just be a matter of adding a wrapper around this, should be pretty simple. If you wanted to see how we use them, you could look in hw_config.c in the timers_init and _start functions.
I’ve been digging into this and using the app_timer is fairly limited depending on the Prescaler. I believe Bluz is running a Prescaler of 0 which means the max duration of an app timer is 512 seconds, going to have to track roll overs etc for the longer duration stuff.
Looking at the Timer class in the Particle devices it would appear that it is rooted in FreeRTOS. My personal vote is duplicate the functionality as much as possible so there is little deviation from Bluz to Photon but not sure from a dev perspective what kind of mess that would create and where break from the Photon way to a Bluz way.
All that being said, @peekay123 your lib is awesome and I would happily just use it as well…maybe it could just be the Timer class for Bluz (after it is updated) giving a like for like dev experience but not getting into FreeRTOS?
@LukeUSMC, after doing some reading I believe the app_timer is the closest thing to the Particle Software Timers and the easiest to implement. To me the 512sec max is not an issue as much as what is the smallest time value (1ms?). On Particle, software timers are run in their own 1ms thread, round-robin style. I believe logically, the same could be said of the app_timers. It might be possible to create wrapper functions to mimic the Software Timer API.
Another interesting API to expose would be the app_scheduler which allows deferring timer callback processing into the loop(). Combined with app_timers, one could sample N data points via an app_timer and then schedule the servicing of that data to asynchronously run in loop(). This functionality is not available per-se on Particle but then neither is bluetooth!
Yeah I think a few mods to spark_wiring_timer.h will map in Timer to app_timers pretty easily. Max is currently set to six with the Millis timer taking one so that leaves fiver user timers available. There isn’t a HAL for that so is that the correct place to modify? I’d love to try!
I was looking at the scheduler too, it isn’t started by Bluz but it could be if the hw_config timer_init was modified slightly (false to true). At least that’s how I read it.
@eric the one thing I’m hanging up on is disposing of a timer. Can you provide a little guidance on that? There isn’t a Nordic function to delete. Also where should the wrapper code go? I’m willing to give it a go to at least shortcut the process for you. I think 4.7 is what the last merge is based on but I’d like to include the “one_shot” timer functionality in 4.9 (which the timer class is greatly changed in). Should I skip the one_shot and worry about that at the next merge?
@peekay123 I like the idea of getting the scheduler wrapped in as well. Similar to the Serial event stuff is how I am understanding it? If an app timer can take sensor readings and the scheduler could then handle data prep and publish all while keeping the loop code very minimal then that’s exactly what I want to do! How could we collaborate on that? PS-Still getting wore out by pointers…hoping doing some stuff that’s more edit based than full on creation I’ll have my ah ha moment.
It would probably be wise to merge in 4.9 regardless, I would like to do that before we do our next release. I can get that done soon and then we can take a shot at this. I haven’t looked, but the specific functions like this are usually in a class under the hal/src/bluz folder, so you would add the function calls there. There must be a file like timers_hal.c or something like that. The file may not be there, it may be in hal/src/template and needs to get moved over, the build system will pick up files from there if they aren’t in the bluz folder. I also changed how this works for the gateway branch, so I will probably merge that in before the next release as well.
Spark_wiring_timer.h calls functions in hal_concurrent.h/c in Dynalib. I’ll work on a 4.9 based version. Are there any intentions to support threading?
So looking now I think that I would shim app_timer_start/stop/create into hal_concurrent which uses os_timer_start/stop/etc calls from the Broadcom sdk.
@LukeUSMC, the nRF51 doesn’t run FreeRTOS so threading, per se, is not implemented. There is no official FreeRTOS support but there are unofficial ports available. So using app_timer and app_scheduler are as close as we get to an RTOS. A solid user-facing API for both of these is crucial IMO.
As for 0.4.9, I agree we need to support it keeping in mind that 0.5.0 is very close to being released though it is primarily aimed at the Electron.
Agreed, since spark_wiring_timer.h (Timer class header) includes concurrent_hal.h/cpp which uses the FreeRTOS timer.h for actual creation and such of Timer class objects…where should Bluz depart from the Photon/Electron methods and establish the nrf51 way? I figure if we can get a Timer class setup and working then the Schedule class (or whatever it is called) would be built upon that.
The main purpose of scheduler is to move the execution of callbacks from an interrupt context to the main context. So I would see using scheduler as an option to other classes like Timer, Interrupt, BLE Data Callbacks, etc. The callbacks from those would either run in the main context or in an interrupt context, so perhaps the user could choose. I wouldn’t explicitly expose the scheduler API.
Right now we don’t use the scheduler for much (if anything). It is sort of all or nothing when it comes to nrf51 drivers, so either all timers use it or none do. We would need to change some of the system firmware to use it or implement our own version, this is what Sandeep did in his BLEPeripheral library.
I am certainly open to using it, or a similar approach, when creating libraries with interrupt callbacks. For now, I had assumed I wouldn’t really use it and any user callbacks would be run in the interrupt context. But I am open to changing that.
@eric, I liken the scheduler to using Software Timers on Particle and telling folks to set a flag in the callback which they read in loop() to execute the supporting code. The scheduler packages that up nicely for the nRF51.
The only catch with all-or-nothing scheduling is that from the examples I’ve seen, a timer callback can so some work and then defer the rest (schedule) to the loop() code. For example, an app_timer callback could collect N samples or count up N times (very short execution) and then deffer to the scheduler.
I hadn’t considered other applications like Interrupt and BLE Data though I can absolutely see the usefulness. A wrapper around the callback creation could allow the user to slit the callback into two parts - immediate and deferred. If only an immediate callback is specified, it is assumed that everything is run in the interrupt/app_timer/BLE data, etc. context. If both are specified then it is assumed that when the immediate callback returns, the scheduler is called with the deferred callback function.
As for app_timer, I noticed there is a create but I could not find a destroy, meaning that I can’t find a way to release a timer in order to create a new one. For example, create a on-shot, destroy it, then create a repeated timer with the same ID but new callback, etc.
It looks like if you stop a timer or when a one_shot is finished, it gets deleted. App_timer in the MCU/Spark_driver_firmware or something like that has all of the app_timer code. Any stopped or non-repeating timer gets canned and the timer list shifts “up” when the timer_list_handler runs.
@LukeUSMC, thanks for the reference. From what I see, STOP or STOP_ALL will delete a single or all timers. On STOP_ALL, the entire timer queue is cleared.
So, based on that, we can’t emulate the full Particle Software Timer API since Particle’s STOP simply stops a timer but leaves it active whereas on nRF51, STOP deletes the timer. Particle has DISPOSE for that. I don’t think that’s an issue as long as documentation is good.
I will try and get the merges done this week, both 4.9 into develop and then the gateway branch into develop, then we can start adding this. There have been some good fixes in the branch so far, so adding the Timer library will probably justify a new release, so we should be able to get to 1.1.49 quickly
Could we wrap it so the same API calls are available and a timer.stop stores the timer settings so when start is called again it gets re-created and started on the fly? Dispose becomes the app_timer_stop without saving the rest.
Since the millis() counter is tied to an app_timer id say we don’t expose any stop_all functionality unless that has a Millis safeguard in it.