Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement override triggers. #825

Merged
merged 23 commits into from
Sep 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3be1f96
Give access to triggers of current container.
floitsch Sep 20, 2023
db250ab
Add more information to triggers.
floitsch Sep 20, 2023
f37718b
Add 'Triggers' class
floitsch Sep 20, 2023
979b353
Add 'deep-sleep-state' abstraction
floitsch Sep 20, 2023
c1bef6b
More refactoring of job states.
floitsch Sep 20, 2023
0a81d74
Implement override triggers.
floitsch Sep 20, 2023
2f6d376
Feedback.
floitsch Sep 25, 2023
2844e92
Feedback.
floitsch Sep 25, 2023
04d6df2
Merge branch 'main' into floitsch/triggers.10.expose
floitsch Sep 25, 2023
89c3700
Merge branch 'floitsch/triggers.10.expose' into floitsch/triggers.20.…
floitsch Sep 25, 2023
756a0d2
Merge branch 'main' into floitsch/triggers.20.more-info
floitsch Sep 25, 2023
4666ba4
Merge branch 'floitsch/triggers.20.more-info' into floitsch/triggers.…
floitsch Sep 25, 2023
a57c8d2
Merge branch 'main' into floitsch/triggers.30.triggers-class
floitsch Sep 25, 2023
6b22c1f
Merge branch 'floitsch/triggers.30.triggers-class' into floitsch/trig…
floitsch Sep 25, 2023
24a989d
Merge branch 'main' into floitsch/triggers.30.triggers-class
floitsch Sep 25, 2023
2e85979
Merge branch 'floitsch/triggers.30.triggers-class' into floitsch/trig…
floitsch Sep 25, 2023
3697aed
Merge branch 'main' into floitsch/triggers.40.deep-sleep-state
floitsch Sep 25, 2023
505d54b
Merge branch 'floitsch/triggers.40.deep-sleep-state' into floitsch/tr…
floitsch Sep 25, 2023
7ac2a2b
Feedback.
floitsch Sep 25, 2023
d7b65f9
Merge branch 'main' into floitsch/triggers.50.deep-sleep-state2
floitsch Sep 26, 2023
d74f558
Merge branch 'floitsch/triggers.50.deep-sleep-state2' into floitsch/t…
floitsch Sep 26, 2023
71f3c90
Merge.
floitsch Sep 26, 2023
78627c0
Feedback.
floitsch Sep 26, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 71 additions & 16 deletions src/service/containers.toit
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ import system.containers
// version will be used instead.

// WAS: import artemis show Trigger
import .pkg-artemis-src-copy.artemis show Trigger
import .pkg-artemis-src-copy.artemis
show
Trigger
TriggerInterval
TriggerPin
TriggerTouch

import .jobs
import .esp32.pin-trigger
Expand Down Expand Up @@ -179,6 +184,26 @@ class Triggers:
if not trigger-gpio-touch: trigger-gpio-touch = {}
trigger-gpio-touch.add value

constructor.from-encoded-list triggers/List:
triggers.do: | encoded/int |
trigger := Trigger.decode encoded
kind := trigger.kind
if kind == Trigger.KIND-BOOT:
trigger-boot = true
else if kind == Trigger.KIND-INSTALL:
trigger-install = true
else if kind == Trigger.KIND-INTERVAL:
trigger-interval = (trigger as TriggerInterval).interval
else if kind == Trigger.KIND-PIN:
pin := (trigger as TriggerPin).pin
level := (trigger as TriggerPin).level
if not trigger-gpio-levels: trigger-gpio-levels = {:}
trigger-gpio-levels[pin] = level
else if kind == Trigger.KIND-TOUCH:
pin := (trigger as TriggerTouch).pin
if not trigger-gpio-touch: trigger-gpio-touch = {}
trigger-gpio-touch.add pin

has-gpio-pin-triggers -> bool:
return trigger-gpio-levels != null

Expand Down Expand Up @@ -218,7 +243,10 @@ class ContainerJob extends Job:

is-background_/bool := false

triggers_/Triggers := Triggers
triggers-default_/Triggers := Triggers
// The triggers that are currently active/armed. They might differ from the
// default triggers if the user called `set-override-triggers`.
triggers-armed_/Triggers := ?

is-triggered_/bool := false
// The reason for why this job was triggered.
Expand All @@ -234,12 +262,27 @@ class ContainerJob extends Job:
description_ = description
pin-trigger-manager_ = pin-trigger-manager
logger_ = logger.with-name name
triggers-armed_ = triggers-default_
super name state
update description

stringify -> string:
return "container:$name"

scheduler-state -> any:
state := super
if identical triggers-armed_ triggers-default_: return state
return [state, triggers-armed_.to-encoded-list]

set-scheduler-state_ state/any -> none:
if state is List:
super state[0]
triggers := state[1]
assert: triggers != null
triggers-armed_ = Triggers.from-encoded-list triggers
else:
super state

is-running -> bool:
return running_ != null

Expand Down Expand Up @@ -274,7 +317,7 @@ class ContainerJob extends Job:
// TODO(kasper): Find a way to reboot the device if
// a critical container keeps restarting.
trigger (Trigger.encode Trigger.KIND-CRITICAL)
else if trigger-interval := triggers_.trigger-interval:
else if trigger-interval := triggers-armed_.trigger-interval:
result := last ? last + trigger-interval : now
if result > now: return result
trigger (Trigger.encode-interval trigger-interval)
Expand All @@ -293,19 +336,30 @@ class ContainerJob extends Job:
last-trigger-reason_ = reason

/** An encoded list (see $Trigger.encode) of all triggers that are active for this job. */
all-active-triggers -> List:
encoded-armed-triggers -> List:
if scheduler-delayed-until_:
// If the job is delayed, then no other trigger is active.
remaining-time-ms := (scheduler-delayed-until_.to-monotonic-us - Time.monotonic-us) / 1000
return [Trigger.encode-delayed remaining-time-ms]

return triggers_.to-encoded-list
return triggers-armed_.to-encoded-list

set-override-triggers new-encoded-triggers/List? -> none:
if not new-encoded-triggers or triggers-default_.to-encoded-list == new-encoded-triggers:
triggers-armed_ = triggers-default_
return

triggers-armed_ = Triggers.from-encoded-list new-encoded-triggers
// Typically we are currently running, and don't need any trigger setup.
// The following call is just in case of race conditions.
if not running_:
pin-trigger-manager_.update-job this

schedule-tune last/JobTime -> JobTime:
// If running the container took a long time, we tune the
// schedule and postpone the next run by making it start
// at the beginning of the next period instead of now.
return Job.schedule-tune-periodic last triggers_.trigger-interval
return Job.schedule-tune-periodic last triggers-armed_.trigger-interval

start -> none:
if running_: return
Expand Down Expand Up @@ -351,40 +405,41 @@ class ContainerJob extends Job:
runlevel_ = Job.RUNLEVEL-CRITICAL

// Reset triggers.
triggers_ = is-critical
triggers-default_ = is-critical
? Triggers
: Triggers.from-description (description.get "triggers")
triggers-armed_ = triggers-default_

has-boot-trigger -> bool:
return triggers_.trigger-boot
return triggers-armed_.trigger-boot

has-install-trigger -> bool:
return triggers_.trigger-install
return triggers-armed_.trigger-install

has-gpio-pin-triggers -> bool:
return triggers_.has-gpio-pin-triggers
return triggers-armed_.has-gpio-pin-triggers

has-touch-triggers -> bool:
return triggers_.has-touch-triggers
return triggers-armed_.has-touch-triggers

has-pin-triggers -> bool:
return has-gpio-pin-triggers or has-touch-triggers

has-pin-trigger pin/int --level/int -> bool:
return triggers_.has-pin-trigger pin --level=level
return triggers-armed_.has-pin-trigger pin --level=level

has-touch-trigger pin/int -> bool:
return triggers_.has-touch-trigger pin
return triggers-armed_.has-touch-trigger pin

do --trigger-gpio-levels/bool [block]:
if not has-gpio-pin-triggers: return
triggers_.trigger-gpio-levels.do: | pin level |
triggers-armed_.trigger-gpio-levels.do: | pin level |
block.call pin level

do --trigger-touch-pins/bool [block]:
if not has-touch-triggers: return
triggers_.trigger-gpio-touch.do: | pin |
triggers-armed_.trigger-gpio-touch.do: | pin |
block.call pin

touch-triggers -> Set:
return triggers_.trigger-gpio-touch
return triggers-armed_.trigger-gpio-touch
6 changes: 4 additions & 2 deletions src/service/esp32/pin-trigger.toit
Original file line number Diff line number Diff line change
Expand Up @@ -319,14 +319,16 @@ class PinTriggerManager:
if high-mask != 0:
// TODO(florian): only some pins are allowed.
logger_.info "setting up external-wakeup trigger any high: $(%b high-mask)"
esp32.enable-external-wakeup high-mask true
catch --trace:
esp32.enable-external-wakeup high-mask true
if low-mask != 0:
logger_.warn "pin triggers for low level are ignored"
else if low-mask != 0:
if low-mask.population-count > 1:
logger_.warn "device will only wake up if all trigger pins are 0"
logger_.info "setting up external-wakeup trigger all low: $(%b low-mask)"
esp32.enable-external-wakeup low-mask false
catch --trace:
esp32.enable-external-wakeup low-mask false

has-touch-triggers := jobs.any: | job/ContainerJob | job.has-touch-triggers

Expand Down
6 changes: 6 additions & 0 deletions src/service/pkg_artemis_src_copy/api/api.toit
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ interface ArtemisService:
container-current-triggers -> List?
static CONTAINER-CURRENT-TRIGGERS-INDEX /int ::= 11

container-current-set-triggers new-triggers/List? -> none
static CONTAINER-CURRENT-SET-TRIGGERS-INDEX /int ::= 12

controller-open --mode/int -> int
static CONTROLLER-OPEN-INDEX /int ::= 6

Expand Down Expand Up @@ -93,6 +96,9 @@ class ArtemisClient extends ServiceClient
container-current-triggers -> List:
return invoke_ ArtemisService.CONTAINER-CURRENT-TRIGGERS-INDEX null

container-current-set-triggers new-triggers/List -> none:
invoke_ ArtemisService.CONTAINER-CURRENT-SET-TRIGGERS-INDEX new-triggers

controller-open --mode/int -> int:
return invoke_ ArtemisService.CONTROLLER-OPEN-INDEX mode

Expand Down
26 changes: 26 additions & 0 deletions src/service/pkg_artemis_src_copy/artemis.toit
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ class Trigger:
if kind == KIND_RESTART: return TriggerRestart value >> 5
return Trigger kind

encode -> int:
return Trigger.encode kind

stringify -> string:
if kind == KIND_BOOT: return "Trigger - boot"
if kind == KIND_INSTALL: return "Trigger - install"
Expand All @@ -134,6 +137,9 @@ class TriggerPin extends Trigger:
constructor .pin --.level:
super Trigger.KIND_PIN

encode -> int:
return Trigger.encode-pin pin --level=level

stringify -> string:
return "Trigger - pin $pin-$level"

Expand All @@ -145,6 +151,9 @@ class TriggerTouch extends Trigger:
constructor .pin:
super Trigger.KIND_TOUCH

encode -> int:
return Trigger.encode-touch pin

stringify -> string:
return "Trigger - touch $pin"

Expand All @@ -153,6 +162,9 @@ class TriggerInterval extends Trigger:
constructor .interval:
super Trigger.KIND_INTERVAL

encode -> int:
return Trigger.encode-interval interval

stringify -> string:
return "Trigger - interval $interval"

Expand All @@ -161,6 +173,9 @@ class TriggerRestart extends Trigger:
constructor .remaining-ms:
super Trigger.KIND_RESTART

encode -> int:
return Trigger.encode-delayed remaining-ms

stringify -> string:
if remaining-ms == 0: return "Trigger - restart"
return "Trigger - restart in $(remaining-ms)ms"
Expand Down Expand Up @@ -216,6 +231,17 @@ interface Container:
*/
triggers -> List

/**
Updates the triggers to the given $triggers list.

These triggers are active until the next time the container is
executed, or until the device is reset.

If $triggers is set to null, then the original triggers are
restored.
*/
set-next-start-triggers triggers/List? -> none
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure yet, but I feel like I want to couple this with the container restart mechanism.

artemis.Container.current.restart --triggers=[ ... ] --delay=(Duration --s=10)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can add this functionality, but Consibio wants to be able to disable a pin-trigger. They might not necessarily need to restart at that point.
It's also easier if the program decides at start-up what its next triggers should be. (Or maybe just after connecting...).
If we force a restart when setting the trigger, then it's quite easy to forget it, or to accidentally not set if if the program crashes...


/**
A channel is a cyclic datastructure that persists a sequence
of distinct elements encoded in individual byte arrays.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,9 @@ class ContainerCurrent implements artemis.Container:
triggers -> List:
encoded-triggers := client_.container-current-triggers
return encoded-triggers.map: artemis.Trigger.decode it

set-next-start-triggers triggers/List? -> none:
encoded-triggers := triggers
? triggers.map: | trigger/artemis.Trigger | trigger.encode
: null
client_.container-current-set-triggers encoded-triggers
15 changes: 14 additions & 1 deletion src/service/service.toit
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ class ArtemisServiceProvider extends ChannelServiceProvider
return container-current-trigger --gid=gid
if index == api.ArtemisService.CONTAINER-CURRENT-TRIGGERS-INDEX:
return container-current-triggers --gid=gid
if index == api.ArtemisService.CONTAINER-CURRENT-SET-TRIGGERS-INDEX:
container-current-set-triggers --gid=gid --new-triggers=arguments
return null
if index == api.ArtemisService.CONTROLLER-OPEN-INDEX:
return controller-open --client=client --mode=arguments
if index == api.ArtemisService.DEVICE-ID-INDEX:
Expand Down Expand Up @@ -134,7 +137,14 @@ class ArtemisServiceProvider extends ChannelServiceProvider
if job is not ContainerJob:
return null
container_job := job as ContainerJob
return (job as ContainerJob).all-active-triggers
return (job as ContainerJob).encoded-armed-triggers

container-current-set-triggers --gid/int --new-triggers/List?:
job := containers_.get --gid=gid
if job is not ContainerJob:
return
container_job := job as ContainerJob
container_job.set-override-triggers new-triggers

controller-open --client/int --mode/int -> ControllerResource:
online := false
Expand All @@ -155,6 +165,9 @@ class ArtemisServiceProvider extends ChannelServiceProvider
container-current-triggers -> List:
unreachable // Here to satisfy the checker.

container-current-set-triggers new-triggers/List -> none:
unreachable // Here to satisfy the checker.

controller-open --mode/int -> int:
unreachable // Here to satisfy the checker.

Expand Down