Skip to content

Commit 19b1170

Browse files
committed
STM32: Tidy up WAKEUP timer handling to ensure the Wakeup is always the first item in the queue
1 parent 97d9d8e commit 19b1170

File tree

6 files changed

+35
-36
lines changed

6 files changed

+35
-36
lines changed

ChangeLog

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
Bangle.js1: dump() now doesn't write out interpreter state as JS (saves 1.5kB Flash)
1111
Espruino Pico: Removed 'tv' library by default to free up flash storage
1212
Fix jshPopIOEventOfType when the event to be popped is right at the start
13+
STM32: Tidy up WAKEUP timer handling to ensure the Wakeup is always the first item in the queue
1314

1415
2v28 : Add `E.internal` as a way to access the 'hidden root' containing Espruino internal variables that previously needed `global["\xff"]`
1516
Bangle.js: Fix back handler not removed when using E.setUI with a back button but without widgets (#2636)

src/jstimer.c

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -289,8 +289,9 @@ int utilTimerGetUnusedIndex(bool wait) {
289289
* task.time is the delay at which to execute the task. If timerOffset!==NULL then
290290
* task.time is relative to the time at which timerOffset=jstGetUtilTimerOffset().
291291
* This allows pulse trains/etc to be scheduled in sync.
292+
* If firstOnly=true, only insert the task if it'll be the first in the queue (otherwise set task type to UET_NONE and exit)
292293
*/
293-
void utilTimerInsertTask(uint8_t taskIdx, uint32_t *timerOffset) {
294+
bool utilTimerInsertTask(uint8_t taskIdx, uint32_t *timerOffset, bool firstOnly) {
294295
assert(!utilTimerIsFull()); // queue should not be full since we had to allocate a task to get the index
295296
UtilTimerTask *task = &utilTimerTaskInfo[taskIdx];
296297

@@ -302,8 +303,14 @@ void utilTimerInsertTask(uint8_t taskIdx, uint32_t *timerOffset) {
302303
int timePassed = utilTimerOn ? (jshGetSystemTime() - utilTimerSetTime) : 0;
303304
// find out where to insert
304305
unsigned char insertPos = utilTimerTasksTail;
305-
while (insertPos != utilTimerTasksHead && utilTimerTaskInfo[utilTimerTasks[insertPos]].time < (task->time+timePassed))
306+
while (insertPos != utilTimerTasksHead && utilTimerTaskInfo[utilTimerTasks[insertPos]].time < (task->time+timePassed)) {
307+
if (firstOnly) { // if we're only allowed to schedule as the first item, we must bail out now
308+
jshInterruptOn();
309+
utilTimerTaskInfo[taskIdx].type = UET_NONE;
310+
return false;
311+
}
306312
insertPos = (insertPos+1) & (UTILTIMERTASK_TASKS-1);
313+
}
307314
bool haveChangedTimer = insertPos==utilTimerTasksTail;
308315
//jsiConsolePrintf("Insert at %d, Tail is %d\n",insertPos,utilTimerTasksTail);
309316
// shift items forward
@@ -336,6 +343,7 @@ void utilTimerInsertTask(uint8_t taskIdx, uint32_t *timerOffset) {
336343
jstRestartUtilTimer();
337344
}
338345
jshInterruptOn();
346+
return true;
339347
}
340348

341349
/// Find a task that 'checkCallback' returns true for. Returns -1 if none found
@@ -460,7 +468,7 @@ bool jstPinOutputAtTime(JsSysTime time, uint32_t *timerOffset, Pin *pins, int pi
460468
for (i=0;i<UTILTIMERTASK_PIN_COUNT;i++)
461469
task->data.set.pins[i] = (Pin)((i<pinCount) ? pins[i] : PIN_UNDEFINED);
462470
task->data.set.value = value;
463-
utilTimerInsertTask(idx, timerOffset);
471+
utilTimerInsertTask(idx, timerOffset, false/*doesn't have to be first*/);
464472
return true;
465473
}
466474

@@ -551,8 +559,8 @@ bool jstPinPWM(JsVarFloat freq, JsVarFloat dutyCycle, Pin pin) {
551559
jshPinSetValue(pin, 1);
552560
uint32_t timerOffset = jstGetUtilTimerOffset();
553561
// now start the 2 PWM tasks
554-
utilTimerInsertTask(onidx, &timerOffset);
555-
utilTimerInsertTask(offidx, &timerOffset);
562+
utilTimerInsertTask(onidx, &timerOffset, false/*doesn't have to be first*/);
563+
utilTimerInsertTask(offidx, &timerOffset, false/*doesn't have to be first*/);
556564
return true;
557565
}
558566

@@ -568,7 +576,7 @@ bool jstExecuteFn(UtilTimerTaskExecFn fn, void *userdata, JsSysTime startTime, u
568576
task->type = UET_EXECUTE;
569577
task->data.execute.fn = fn;
570578
task->data.execute.userdata = userdata;
571-
utilTimerInsertTask(idx, timerOffset);
579+
utilTimerInsertTask(idx, timerOffset, false/*doesn't have to be first*/);
572580
return true;
573581
}
574582

@@ -581,35 +589,18 @@ bool jstStopExecuteFn(UtilTimerTaskExecFn fn, void *userdata) {
581589
}
582590

583591
/// Set the utility timer so we're woken up in whatever time period
584-
bool jstSetWakeUp(JsSysTime period) {
592+
void jstSetWakeUp(JsSysTime period) {
585593
bool hasTimer = false;
586594
int wakeupTime = (int)period;
587595
int nextTime;
588596

589-
590-
// work out if we're waiting for a timer,
591-
// and if so, when it's going to be
592-
jshInterruptOff();
593-
if (utilTimerTasksTail!=utilTimerTasksHead) {
594-
hasTimer = true;
595-
nextTime = utilTimerTaskInfo[utilTimerTasks[utilTimerTasksTail]].time;
596-
}
597-
jshInterruptOn();
598-
JsSysTime currTime = jshGetSystemTime();
599-
if (hasTimer && ((currTime+wakeupTime) >= (utilTimerSetTime+nextTime))) {
600-
// we already had a timer, and it's going to wake us up sooner.
601-
// don't create a WAKEUP timer task
602-
return true;
603-
}
604-
605597
int idx = utilTimerGetUnusedIndex(false/*don't wait*/);
606-
if (idx<0) return false; // no free tasks!
598+
if (idx<0) return; // no free tasks!
607599
UtilTimerTask *task = &utilTimerTaskInfo[idx];
608600
task->type = UET_WAKEUP;
609601
task->time = wakeupTime;
610602
task->repeatInterval = 0;
611-
utilTimerInsertTask(idx, NULL);
612-
return true;
603+
utilTimerInsertTask(idx, NULL, true/* must be first! If not something else will wake us first so don't bother. */);
613604
}
614605

615606
/** If the first timer task is a wakeup task, remove it. This stops
@@ -664,7 +655,7 @@ int jstStartSignal(JsSysTime startTime, JsSysTime period, Pin pin, Pin npin, JsV
664655
task->data.buffer.nextBuffer = 0;
665656
}
666657
jstUtilTimerSetupBuffer(task);
667-
utilTimerInsertTask(idx, NULL);
658+
utilTimerInsertTask(idx, NULL, false/*doesn't have to be first*/);
668659
return idx;
669660
}
670661

src/jstimer.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ bool jstExecuteFn(UtilTimerTaskExecFn fn, void *userdata, JsSysTime startTime, u
166166
bool jstStopExecuteFn(UtilTimerTaskExecFn fn, void *userdata);
167167

168168
/// Set the utility timer so we're woken up in whatever time period
169-
bool jstSetWakeUp(JsSysTime period);
169+
void jstSetWakeUp(JsSysTime period);
170170

171171
/** If the first timer task is a wakeup task, remove it. This stops
172172
* us filling the timer full of wakeup events if we wake up from sleep
@@ -200,8 +200,9 @@ int utilTimerGetUnusedIndex(bool wait);
200200
* task.time is the delay at which to execute the task. If timerOffset!==NULL then
201201
* task.time is relative to the time at which timerOffset=jstGetUtilTimerOffset().
202202
* This allows pulse trains/etc to be scheduled in sync.
203+
* If firstOnly=true, only insert the task if it'll be the first in the queue (otherwise set task type to UET_NONE and exit)
203204
*/
204-
void utilTimerInsertTask(uint8_t taskIdx, uint32_t *timerOffset);
205+
bool utilTimerInsertTask(uint8_t taskIdx, uint32_t *timerOffset, bool firstOnly);
205206

206207
/// Find a task that 'checkCallback' returns true for. Returns -1 if none found
207208
int utilTimerFindTask(bool (checkCallback)(UtilTimerTask *task, void* data), void *checkCallbackData);

src/jswrap_stepper.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ JsVar *jswrap_stepper_moveTo(JsVar *stepper, int position, JsVar *options) {
320320
task->data.step.pattern[2] = 0b00010010;
321321
task->data.step.pattern[3] = 0b01001000;
322322
jswrap_stepper_getPattern(stepper, task->data.step.pattern);
323-
utilTimerInsertTask(idx, NULL);
323+
utilTimerInsertTask(idx, NULL, false/*doesn't have to be first*/);
324324
// And finally set it up
325325
jsvObjectSetChildAndUnLock(stepper, "timer", jsvNewFromInteger(idx));
326326
jsvObjectSetChildAndUnLock(stepper, "running", jsvNewFromBool(true));

src/jswrap_timer.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@ void jstRunInterruptingJS() {
7171
unsigned int len = 0;
7272
if (jshPopIOEventOfType(EV_RUN_INTERRUPT_JS, data, &len))
7373
jstOnRunInterruptJSEvent(data, len);
74+
/*if (jshIsTopEvent(EV_RUN_INTERRUPT_JS)) {
75+
jshPopIOEvent(data, &len);
76+
jstOnRunInterruptJSEvent(data, len);
77+
} else/
78+
execInfo.execute &= ~EXEC_RUN_INTERRUPT_JS; // stop until idle
79+
*/
7480
}
7581

7682

@@ -320,7 +326,7 @@ int jswrap_timer_add(JsVar *timer) {
320326
}
321327
task->type = evtType; // set type here, as we may have returned with error earlier
322328
jsvUnLock(fn);
323-
utilTimerInsertTask(idx, NULL);
329+
utilTimerInsertTask(idx, NULL, false/*doesn't have to be first*/);
324330
return idx;
325331
}
326332

@@ -332,10 +338,10 @@ int jswrap_timer_add(JsVar *timer) {
332338
"generate" : "jswrap_timer_remove",
333339
"params" : [
334340
["timerID","int","The ID of the timer to remove"]
335-
]
341+
],
342+
"return" : ["bool","`true` on success or `false` if there was no timer with that ID"]
336343
}
337344
*/
338-
void jswrap_timer_remove(int id) {
339-
if (!utilTimerRemoveTask(id))
340-
jsExceptionHere(JSET_ERROR, "No timer with ID %d", id);
345+
bool jswrap_timer_remove(int id) {
346+
return utilTimerRemoveTask(id);
341347
}

src/jswrap_timer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
JsVar *jswrap_timer_list();
2020
JsVar *jswrap_timer_get(int id);
2121
int jswrap_timer_add(JsVar *timer);
22-
void jswrap_timer_remove(int id);
22+
bool jswrap_timer_remove(int id);
2323

2424
/** This is called if a EV_RUN_INTERRUPT_JS is received, or when a EXEC_RUN_INTERRUPT_JS is set.
2525
It executes JavaScript code that was pushed to the queue by a require("timer").add({type:"EXEC", fn:myFunction... */

0 commit comments

Comments
 (0)