I would like to execute a function every 10ms in a task called at 1ms. Do you know if there is a function to do that without blocking the task please ?
Have a good day!
static void app_task(void *arg)
{
int period_ms = 1000;
TimeOut_t timeout;
TickType_t period_tick = pdMS_TO_TICKS(period_ms); vTaskSetTimeOutState(&timeout);
for (;;) {
if(xTaskCheckForTimeOut(&timeout, &period_tick) != pdFALSE) {
vTaskSetTimeOutState(&timeout);
period_tick = pdMS_TO_TICKS(period_ms);
/* task */
}
}
}
I’d use xTaskCheckForTimeOut paired with vTaskSetTimeOutState. See the example in the API docs https://freertos.org/xTaskCheckForTimeOut.html
Thanks HS2, it works well.
Here a sample of how I proceed for executing some code every 10ms in a 1ms task.
xTimeOutType x_timeout;
portTickType openTimeout;
vTaskSetTimeOutState(&x_timeout);
openTimeout = 10; /*ms*/
while(1)
{
//...
//...
if(xTaskCheckForTimeOut(&x_timeout, &openTimeout) == pdTRUE)
{
// do some stuff here
openTimeout = 10; /*reload the 10ms*/
}
//...
//...
}
Related
I have a KMM app, and there is code:
fun getWeather(callback: (WeatherInfo) -> Unit) {
println("Start loading")
GlobalScope.launch(ApplicationDispatcher) {
while (true) {
val response = httpClient.get<String>(API_URL) {
url.parameters.apply {
set("q", "Moscow")
set("units", "metric")
set("appid", weatherApiKey())
}
println(url.build())
}
val result = Json {
ignoreUnknownKeys = true
}.decodeFromString<WeatherApiResponse>(response).main
callback(result)
// because ApplicationDispatcher on IOS do not support delay
withContext(Dispatchers.Default) { delay(DELAY_TIME) }
}
}
}
And if I replace withContext(Dispatchers.Default) { delay(DELAY_TIME) } with delay(DELAY_TIME) execution is never returned to while cycle and it will have only one iteration.
And ApplicationDispatcher for IOS looks like:
internal actual val ApplicationDispatcher: CoroutineDispatcher = NsQueueDispatcher(dispatch_get_main_queue())
internal class NsQueueDispatcher(
private val dispatchQueue: dispatch_queue_t
) : CoroutineDispatcher() {
override fun dispatch(context: CoroutineContext, block: Runnable) {
dispatch_async(dispatchQueue) {
block.run()
}
}
}
And from delay source code I can guess, that DefaultDelay should be returned and there is should be similar behaviour with/without withContext(Dispatchers.Default)
/** Returns [Delay] implementation of the given context */
internal val CoroutineContext.delay: Delay get() = get(ContinuationInterceptor) as? Delay ?: DefaultDelay
Thanks!
P.S. I got ApplicationDispatcher from ktor-samples.
Probably ApplicationDispatcher is some old stuff, you don't need to use it anymore:
CoroutineScope(Dispatchers.Default).launch {
}
or
MainScope().launch {
}
And don't forget to use -native-mt version of coroutines, more info in this issue
Sometime the script being evaluated should be stopped by force, but I can't find a way to achieve this. Someone pointed out JSContextGroupSetExecutionTimeLimit might work, but It doesn't in my testing, can anyone help?
Another reference: https://github.com/phoboslab/JavaScriptCore-iOS/issues/14
My code:
int extendTerminateCallbackCalled = 0;
static bool extendTerminateCallback(JSContextRef ctx, void *context)
{
extendTerminateCallbackCalled++;
if (extendTerminateCallbackCalled == 2) {
JSContextGroupRef contextGroup = JSContextGetGroup(ctx);
JSContextGroupSetExecutionTimeLimit(contextGroup, .200f, extendTerminateCallback, 0);
return false;
}
return true;
}
+ (void)stop
{
JSGlobalContextRef ref = [_context JSGlobalContextRef];
JSContextGroupRef contextGroup = JSContextGetGroup(ref);
JSContextGroupSetExecutionTimeLimit(contextGroup, .200f, extendTerminateCallback, 0);
}
Here is an idea of possible approach
+ (void)stop
{
JSContext *context = [JSContext currentContext]; // or whichever your
// set property of JS global object to specific know value
// that should be checked inside JS code regularly during
// long operations and interrupt self execution
context[#"externallyCancelled"] = #(YES);
}
This is related to is there any way to cancel a dart Future?
In my case, there are no HTTP, just expensive calculations. I have a table/list which I scroll through. As the elements become visible, I generate futures to show the calculation results. But if I (the end user) scroll quickly, some results will have "scrolled out of view" and will no longer required. This could be a large number, and would seriously delay the return of futures (results) that are to be usefully :-) displayed in currently visible elements. Can something be done about that? cheers, Steve
You could just set a flag which indicates to the delayed code (run from futures) that the result isn't needed anymore.
When the delayed code is called it just returns.
library cancel_future;
import 'dart:async' show Future, Timer;
import 'dart:math' show Random;
typedef void TaskFunction(Task task);
// Container for a task
class Task {
// an assigned task id
final id;
// data to process
int data;
// Indicate to the task function, that it should stop processing
bool isCanceled = false;
// The task function must set this flat to true when all work is done.
bool isFinished = false;
// The task function which processed the data and sets the result.
TaskFunction fn;
// The result set by the task function when it finished processing.
int result;
Task(this.id, this.data, this.fn);
// Start processing the task.
void execute() => fn(this);
}
final rnd = new Random();
void main(List<String> args) {
// create tasks
final tasks = new List<Task>.from(generate());
// start all tasks
tasks.forEach((t) => t.execute());
// after random delay cancel all unfinished tasks
new Future.delayed(new Duration(seconds: rnd.nextInt(10)), () {
tasks.forEach((t) {
if (!t.isFinished) {
t.isCanceled = true;
}
});
}).then((_) {
// check results
int done = 0;
int canceled = 0;
tasks.forEach((t) {
print(
'Task id: ${t.id}; isCanceled: ${t.isCanceled}; isFinished: ${t.isFinished}; data: ${t.data}; result: ${t.result}');
if (t.isFinished) {
done++;
}
if (t.isCanceled) {
canceled++;
}
});
print('Canceled: $canceled.');
print('Done: $done.');
});
}
// geneator for job 100 jobs
Iterable<Task> generate() sync* {
int i = 0;
while (i++ < 100) {
yield new Task(i, rnd.nextInt(100), calc);
}
}
// job function
void calc(Task t) {
// do a bit of work every 100ms to simulate longer processing
new Timer.periodic(new Duration(milliseconds: 100), (timer) {
var result = 0;
// check if jost was canceled and stop processing in case it was.
if (t.isCanceled) {
timer.cancel();
return;
}
// while not finished do a chunk of work
if (result < t.data) {
result++;
} else {
// finished - clean up and store result
t.isFinished = true;
t.result = result;
timer.cancel();
}
});
}
When I run my method from the constructor of the mainscreen it works, but if invoked in the timer then I get the error.
Here is my method:
public void buildDesc(){
try {
JSONObject event = array.getJSONObject(currentPage);
String title = event.getString("title");
String by = event.getString("by");
String by_name = event.getString("by_name");
String summary = event.getString("summary");
int nid = event.getInt("nid");
vfm.add(new LabelField(title));
System.out.println("The Title:"+title);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
And the timer:
timer = new Timer();//Create the timer to loop the events every 5 seconds
timer.scheduleAtFixedRate(new TimerTask(){
public void run() {
currentPage++;
if(currentPage > 3){
currentPage = 0;
}
System.out.println("Page Position:"+pagePosition(currentPage+1));
gallery.setHorizontalScroll(pagePosition(currentPage));
buildDesc();
}
}, 0, 10000);
I read a Android question that says, perhaps, I can't make changes to the UI if not on the UIThread?
I think your hunch is right, in BlackBerry you shouldn't do any work on the Ui thread. I guess the Timer thread is getting terminated for it's behaviour which is why you are getting an IllegalStateException. A quick guide to the UI thread can be found here.
Try :
timer = new Timer();//Create the timer to loop the events every 5 seconds
timer.scheduleAtFixedRate(new TimerTask(){
public void run() {
currentPage++;
if(currentPage > 3){
currentPage = 0;
}
System.out.println("Page Position:"+pagePosition(currentPage+1));
synchronized(UiApplication.getUiApplication().getEventLock())) {
// UI Code here
gallery.setHorizontalScroll(pagePosition(currentPage));
buildDesc();
}
}
}, 0, 10000);
Note: The above is untested.
I'm trying to use isVisible() within a loop to create a waitForElement type of a function for my iOS UIAutomation. When I try to use the following code, it fails while waiting for an element when a new screen pops up. The element is clearly there because if I do a delay(2) before tapping the element it works perfectly fine. How is everyone else accomplishing this, because I am at a loss...
Here's the waitForElement code that I am using:
function waitForElement(element, timeout, step) {
if (step == null) {
step = 0.5;
}
if (timeout == null) {
timeout = 10;
}
var stop = timeout/step;
for (var i = 0; i < stop; i++) {
if (element.isVisible()) {
return;
}
target.delay(step);
}
element.logElement();
throw("Not visible");
}
Here is a simple wait_for_element method that could be used:
this.wait_for_element = function(element, preDelay) {
if (!preDelay) {
target.delay(0);
}
else {
target.delay(preDelay);
}
var found = false;
var counter = 0;
while ((!found) && (counter < 60)) {
if (!element.isValid()) {
target.delay(0.5);
counter++;
}
else {
found = true;
target.delay(1);
}
}
}
I tend to stay away from my wait_for_element and look for any activityIndicator objects on screen. I use this method to actual wait for the page to load.
this.wait_for_page_load = function(preDelay) {
if (!preDelay) {
target.delay(0);
}
else {
target.delay(preDelay);
}
var done = false;
var counter = 0;
while ((!done) && (counter < 60)) {
var progressIndicator = UIATarget.localTarget().frontMostApp().windows()[0].activityIndicators()[0];
if (progressIndicator != "[object UIAElementNil]") {
target.delay(0.25);
counter++;
}
else {
done = true;
}
}
target.delay(0.25);
}
Here is a simple and better one using recursion. "return true" is not needed but incase u want it.
waitForElementToDismiss:function(elementToWait,waitTime){ //Using recursion to wait for an element. pass in 0 for waitTime
if(elementToWait && elementToWait.isValid() && elementToWait.isVisible() && (waitTime < 30)){
this.log("Waiting for element to invisible");
target.delay(1);
this.waitForElementToDismiss(elementToWait, waitTime++);
}
if(waitTime >=30){
fail("Possible login failed or too long to login. Took more than "+waitTime +" seconds")
}
return true;
}
Solution
I know this is an old question but here is my solution for a situation where I have to perform a repetitive task against a variable timed event. Since UIAutomation runs on javascript I use a recursive function with an empty while loop that checks the critical control state required before proceeding to the next screen. This way one never has to hard code a delay.
// Local target is the running simulator
var target = UIATarget.localTarget();
// Get the frontmost app running in the target
var app = target.frontMostApp();
// Grab the main window of the application
var window = app.mainWindow();
//Get the array of images on the screen
var allImages = window.images();
var helpButton = window.buttons()[0];
var nextButton = window.buttons()[2];
doSomething();
function doSomething ()
{
//only need to tap button for half the items in array
for (var i=0; i<(allImages.length/2); i++){
helpButton.tap();
}
//loop while my control is NOT enabled
while (!nextButton.isEnabled())
{
//wait
}
//proceed to next screen
nextButton.tap();
//go again
doSomething();
}