Skip to content

Commit ad7cfa2

Browse files
committed
First commit of the survey default / example RTK app
1 parent b9f6734 commit ad7cfa2

File tree

9 files changed

+1170
-0
lines changed

9 files changed

+1170
-0
lines changed

examples/containers/base-apps.toit

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import lightbug.devices as devices
2+
import lightbug.messages as messages
3+
import lightbug.modules.comms.message-handler show MessageHandler
4+
import lightbug.modules.strobe.strobe show Strobe
5+
import lightbug.protocol as protocol
6+
import lightbug.apps as apps
7+
import lightbug.apps.survey show SurveyApp
8+
import log
9+
10+
import watchdog.provider
11+
import watchdog show WatchdogServiceClient
12+
13+
LOG-LEVEL ::= log.WARN-LEVEL
14+
15+
main:
16+
provider.main
17+
client := WatchdogServiceClient
18+
client.open
19+
dog := client.create "lb/apps"
20+
21+
device := devices.I2C
22+
--log-level=LOG-LEVEL
23+
--with-default-handlers=false
24+
--background=false
25+
apps := apps.Apps device dog
26+
27+
// Listen for "Actions" button presses...
28+
apps.start

examples/package.lock

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
sdk: ^2.0.0-alpha.145
22
prefixes:
33
lightbug: ..
4+
watchdog: toit-watchdog
45
packages:
56
..:
67
path: ..
78
prefixes:
89
coordinate: toit-coordinate
910
http: pkg-http
11+
watchdog: toit-watchdog
1012
pkg-http:
1113
url: github.com/toitlang/pkg-http
1214
name: http
@@ -17,3 +19,8 @@ packages:
1719
name: coordinate
1820
version: 1.0.0
1921
hash: 5db8272fdfbdc0b2e017280940dc537e5e64b361
22+
toit-watchdog:
23+
url: github.com/toitware/toit-watchdog
24+
name: watchdog
25+
version: 1.4.1
26+
hash: 2621b25fca45f4f91c0b951f3658f3c18821edc4

examples/package.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
dependencies:
22
lightbug:
33
path: ..
4+
watchdog:
5+
url: github.com/toitware/toit-watchdog
6+
version: ^1.4.1

package.lock

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ sdk: ^2.0.0-alpha.145
22
prefixes:
33
coordinate: toit-coordinate
44
http: pkg-http
5+
watchdog: toit-watchdog
56
packages:
67
pkg-http:
78
url: github.com/toitlang/pkg-http
@@ -13,3 +14,8 @@ packages:
1314
name: coordinate
1415
version: 1.0.0
1516
hash: 5db8272fdfbdc0b2e017280940dc537e5e64b361
17+
toit-watchdog:
18+
url: github.com/toitware/toit-watchdog
19+
name: watchdog
20+
version: 1.4.1
21+
hash: 2621b25fca45f4f91c0b951f3658f3c18821edc4

package.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@ dependencies:
77
http:
88
url: github.com/toitlang/pkg-http
99
version: ^2.8.1
10+
watchdog:
11+
url: github.com/toitware/toit-watchdog
12+
version: ^1.4.1

src/apps/apps.toit

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import ..devices
2+
import ..services
3+
import ..messages.messages_gen as messages
4+
import .survey
5+
import ..modules.eink.menu-selection show MenuSelection
6+
import .survey.eink-batch show eink-do-batch
7+
import .survey.strobe-once show strobe-once
8+
import log
9+
import watchdog show Watchdog
10+
11+
class Apps:
12+
13+
device_/Device
14+
dog_/Watchdog
15+
is-running_/bool := false
16+
showing-page_/int := 0
17+
menu-selection/MenuSelection? := null
18+
app_/any? := null // TODO make an app interface?
19+
logger_/log.Logger := log.default.with-name "apps"
20+
buttons-subscriber-id_/int? := null
21+
22+
MENU-OPTIONS := [
23+
"Survey",
24+
"Reboot",
25+
"Go Back",
26+
]
27+
MENU-OPTION-SURVEY := 0
28+
MENU-OPTION-REBOOT:= 1
29+
MENU-OPTION-GO-BACK := 2
30+
31+
PAGE-HOME := 1
32+
PAGE-MENU := 20
33+
34+
constructor device/Device dog/Watchdog:
35+
device_ = device
36+
dog_ = dog
37+
self := this
38+
39+
show-home:
40+
eink-do-batch --important:
41+
// logger_.info "HOME"
42+
device_.eink.show-preset --page-id=PAGE-HOME
43+
showing-page_ = PAGE-HOME
44+
menu-selection = null
45+
46+
show_menu:
47+
eink-do-batch --important:
48+
// logger_.info "MENU"
49+
device_.eink.send-menu --page-id=PAGE-MENU --items=MENU-OPTIONS --selected-item=0
50+
showing-page_ = PAGE-MENU
51+
menu-selection = MenuSelection --start=0 --size=MENU-OPTIONS.size
52+
53+
// Basic app control, similar to SurveyApp.
54+
start:
55+
// logger_.info "START"
56+
is-running_ = true
57+
showing-page_ = PAGE-HOME // We assume we start on the home page..
58+
self := this
59+
60+
// Subscribe to buttons if we're not already subscribed.
61+
if not buttons-subscriber-id_:
62+
e := catch:
63+
id := device_.buttons.subscribe --timeout=null --callback=(:: |button-data|
64+
if button-data.duration <= 0:
65+
// Not actually a press... TODO make this nicer
66+
else:
67+
task::
68+
strobe-once:
69+
device_.strobe.blue
70+
sleep --ms=50
71+
device_.strobe.off
72+
if button-data.duration >= 3000: // 3s any button = home (for now)
73+
show-home
74+
else if self.app_ and self.app_.is-running:
75+
// If an app is running, let it handle button presses
76+
else if showing-page_ == PAGE-HOME: // TODO use a preset page const ID
77+
if button-data.button-id == messages.ButtonPress.BUTTON-ID-RIGHT-DOWN:
78+
self.show_menu
79+
else if showing-page_ == PAGE-MENU:
80+
if button-data.button-id == messages.ButtonPress.BUTTON-ID-ACTION:
81+
if menu-selection.current == MENU-OPTION-SURVEY:
82+
task:: open-survey-app
83+
else if menu-selection.current == MENU-OPTION-REBOOT:
84+
log.info "Rebooting device"
85+
device_.comms.send messages.CPU1Reset.do-msg
86+
else if menu-selection.current == MENU-OPTION-GO-BACK:
87+
show-home
88+
else if button-data.button-id == messages.ButtonPress.BUTTON-ID-RIGHT-DOWN:
89+
menu-selection.up
90+
else if button-data.button-id == messages.ButtonPress.BUTTON-ID-LEFT-UP:
91+
menu-selection.down
92+
else:
93+
// logger_.info "BTN miss $button-data"
94+
)
95+
96+
if not id:
97+
logger_.warn "BTN sub fail"
98+
else:
99+
buttons-subscriber-id_ = id
100+
logger_.warn "BTN sub $(id)"
101+
if e:
102+
logger_.error "BTN sub fail $e"
103+
104+
open-survey-app:
105+
// logger_.info "OPEN SURVEY"
106+
stop
107+
app_ = SurveyApp device_ this dog_
108+
app_.start
109+
app_.show-survey
110+
111+
stop:
112+
// logger_.info "STOP"
113+
showing-page_ = 0 // We no longer assume to know
114+
is-running_ = false
115+
// Unsubscribe from buttons if we have a subscriber id
116+
if buttons-subscriber-id_:
117+
e := catch: device_.buttons.unsubscribe --subscriber-id=buttons-subscriber-id_ --timeout=null
118+
// Ignore errors from unsubscribe but clear our id.
119+
buttons-subscriber-id_ = null
120+
121+
is-running -> bool:
122+
return is-running_

src/apps/survey/eink-batch.toit

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import monitor
2+
import log
3+
4+
eink-sem := monitor.Semaphore --count=1 --limit=1
5+
eink-last-draw-ago_/Time := Time.now
6+
7+
// Perform a batch of actions in a single task to avoid interleaving with other
8+
// async calls.
9+
// Used to ensure that multiple messages intended for a single eink update, are
10+
// sent together without other async calls interleaving.
11+
//
12+
// --important: if true, will wait indefinitely for the mutex, otherwise will not
13+
// draw if the mutex is not available immediately.
14+
//
15+
// In the future, we might advance this further, to allow queuing of important?
16+
// Overwriting of older updates etc?
17+
//
18+
// Ultimately this should be moved to the primary eink module for reuse in a generic way
19+
// as part of the lightbug package.
20+
eink-do-batch --important/bool=false [block]:
21+
if not important:
22+
// Skip non important things, if other eink messages are actively being sent
23+
if eink-sem.count == 0: // If there is no room
24+
return
25+
26+
// If we are not actively sending, but we have drawn recently, skip non important
27+
wait-until := eink-last-draw-ago_ + (Duration --ms=1000)
28+
if wait-until >= Time.now:
29+
return
30+
31+
t := 5000
32+
if important:
33+
t = 10000
34+
35+
// Otherwise, lock and draw..
36+
eink-sem.down
37+
e := catch:
38+
with-timeout --ms=t:
39+
block.call
40+
if e:
41+
log.warn "$e"
42+
eink-last-draw-ago_ = Time.now
43+
eink-sem.up

src/apps/survey/strobe-once.toit

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import monitor
2+
import log
3+
4+
strobe-sem := monitor.Semaphore --count=1 --limit=1
5+
6+
// Rather than needing this in the survey app, move the ability to solve this problem into the strobe module.
7+
//
8+
// In essence the problem is that there is no "flash" ability of the strobe package.
9+
// So apps end up doing something like this...
10+
//
11+
// device_.strobe.blue
12+
// sleep --ms=50
13+
// device_.strobe.off
14+
//
15+
// And if they do this multiple times in quick succession, you can end up with overlapping strobes
16+
// ON SLEEP ON SLEEP OFF OFF for example
17+
18+
strobe-once [block]:
19+
// Skip all strobes if the strobe is busy
20+
if strobe-sem.count == 0: // If there is no room
21+
log.debug "STROBE busy skip"
22+
return
23+
24+
// Otherwise, lock and strobe..
25+
strobe-sem.down
26+
e := catch:
27+
with-timeout --ms=1000:
28+
block.call
29+
if e:
30+
log.warn "$e"
31+
strobe-sem.up

0 commit comments

Comments
 (0)