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

Add hardware-watchdog abstraction. #8

Merged
merged 5 commits into from
Feb 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 8 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
version: 2
updates:
- package-ecosystem: "github-actions" # Necessary to update action hashs
directory: "/"
schedule:
interval: "weekly"
# Allow up to 3 opened pull requests for github-actions versions
open-pull-requests-limit: 3
50 changes: 50 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Zero-Clause BSD License

# Copyright (C) 2024 Toitware ApS.

# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted.

# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
# FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.

name: CI

on:
push:
release:
types: [published]

jobs:
build:
strategy:
matrix:
os: [ ubuntu-latest, windows-latest, macos-latest ]
# The versions should contain (at least) the lowest requirement
# and a version that is more up to date.
toit-version: [ v2.0.0-alpha.118, latest ]
include:
- toit-version: v2.0.0-alpha.118
version-name: old
- toit-version: latest
version-name: new

name: CI - ${{ matrix.os }} - ${{ matrix.version-name }}

runs-on: ${{ matrix.os }}

steps:
- uses: actions/checkout@v4

- uses: toitlang/action-setup@v1
with:
toit-version: ${{ matrix.toit-version }}

- name: Test
run: |
make test
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Publish
uses: toitlang/pkg-publish@v1.3.0
uses: toitlang/pkg-publish@v1.4.0
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.packages/
/build/
10 changes: 10 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright (C) 2024 Toitware ApS.
# Use of this source code is governed by a Zero-Clause BSD license that can
# be found in the tests/TESTS_LICENSE file.

cmake_minimum_required(VERSION 3.23)

project(watchdog NONE)

enable_testing()
add_subdirectory(tests)
27 changes: 27 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright (C) 2024 Toitware ApS.
# Use of this source code is governed by a Zero-Clause BSD license that can
# be found in the tests/LICENSE file.

all: test

.PHONY: build/CMakeCache.txt
build/CMakeCache.txt:
$(MAKE) rebuild-cmake

install-pkgs: rebuild-cmake
cmake --build build --target install-pkgs

test: install-pkgs rebuild-cmake
cmake --build build --target check

# We rebuild the cmake file all the time.
# We use "glob" in the cmakefile, and wouldn't otherwise notice if a new
# file (for example a test) was added or removed.
# It takes <1s on Linux to run cmake, so it doesn't hurt to run it frequently.
rebuild-cmake:
mkdir -p build
# We need to set a build type, otherwise cmake won't run nicely on Windows.
# The build-type is otherwise unused.
cmake -B build -DCMAKE_BUILD_TYPE=Debug

.PHONY: all test rebuild-cmake install-pkgs
20 changes: 20 additions & 0 deletions src/esp32.toit
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright (C) 2024 Toitware ApS. All rights reserved.
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file.

import esp32

import .provider show SystemWatchdog

class SystemWatchdogEsp32 implements SystemWatchdog:
start --ms/int:
esp32.watchdog-init --ms=ms

feed -> none:
esp32.watchdog-reset

stop -> none:
esp32.watchdog-deinit

reboot -> none:
esp32.deep-sleep Duration.ZERO
57 changes: 49 additions & 8 deletions src/provider.toit
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,62 @@
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file.

import esp32
import log
import monitor
import system.services show ServiceProvider ServiceResource ServiceHandler
import .api.service
import .esp32 show SystemWatchdogEsp32

interface SystemWatchdog:
/**
Starts the system watchdog timer.

The watchdog will reset the system if it isn't fed within $ms milliseconds.
The system watchdog may have a coarser granularity than the given $ms.
*/
start --ms/int

/**
Feeds the system watchdog.

# Aliases
- `kick`
- `reset`
*/
feed -> none

/**
Stops the system watchdog.
*/
stop -> none

/**
Reboots the system.

This is called if a watchdog isn't fed in time, but the system
watchdog still has time left.
*/
reboot -> none

class WatchdogServiceProvider extends ServiceProvider
implements ServiceHandler:

static GRANULARITY-MS ::= 2_000

dogs_/Map ::= {:} // From string to Watchdog.
system-watchdog_/SystemWatchdog
system-watchdog-task_/Task? := null
logger_/log.Logger
mutex_/monitor.Mutex ::= monitor.Mutex
granularity-ms_/int

constructor --logger/log.Logger=((log.default.with-name "watchdog").with-level log.ERROR-LEVEL):
constructor
--logger/log.Logger=((log.default.with-name "watchdog").with-level log.ERROR-LEVEL)
--system-watchdog/SystemWatchdog = SystemWatchdogEsp32
--granularity-ms/int = GRANULARITY-MS:
logger_ = logger
system-watchdog_ = system-watchdog
granularity-ms_ = granularity-ms
super "watchdog" --major=1 --minor=0
provides WatchdogService.SELECTOR --handler=this

Expand Down Expand Up @@ -67,23 +105,26 @@ class WatchdogServiceProvider extends ServiceProvider

mutex_.do:
logger_.debug "starting system watchdog"
esp32.watchdog-init --ms=GRANULARITY-MS
system-watchdog_.start --ms=granularity-ms_
system-watchdog-task_ = task::
try:
while true:
too-late := false
dogs_.do --values: | dog/Watchdog |
if dog.is-too-late:
logger_.fatal "watchdog too late" --tags={ "id": dog.id }
logger_.error "watchdog too late" --tags={ "id": dog.id }
too-late = true

if too-late:
esp32.deep-sleep Duration.ZERO
// Feed the system watchdog one last time then request to reboot.
// This allows the system to clean up before rebooting.
mutex_.do: system-watchdog_.feed
system-watchdog_.reboot
else:
// Feed the system watchdog.
logger_.debug "feeding system watchdog"
mutex_.do: esp32.watchdog-reset
sleep --ms=(GRANULARITY-MS / 2)
mutex_.do: system-watchdog_.feed
sleep --ms=(granularity-ms_ / 2)
finally:
system-watchdog-task_ = null

Expand All @@ -96,7 +137,7 @@ class WatchdogServiceProvider extends ServiceProvider
// Shutdown the system watchdog.
mutex_.do:
logger_.info "stopping system watchdog"
esp32.watchdog-deinit
system-watchdog_.stop

system-watchdog-task_.cancel

Expand Down
61 changes: 61 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Copyright (C) 2024 Toitware ApS.
# Use of this source code is governed by a Zero-Clause BSD license that can
# be found in the tests/LICENSE file.

file(GLOB TESTS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*_test.toit" "*-test.toit" "*_test_slow.toit" "*-test-slow.toit")

# Add windows exe extension.
set(TOIT_EXEC "toit.run${CMAKE_EXECUTABLE_SUFFIX}" CACHE FILEPATH "The executable used to run the tests")
set(TPKG_EXEC "toit.pkg${CMAKE_EXECUTABLE_SUFFIX}" CACHE FILEPATH "The executable used to install the packages")
set(TEST_TIMEOUT 40 CACHE STRING "The maximal amount of time each test is allowed to run")
set(SLOW_TEST_TIMEOUT 200 CACHE STRING "The maximal amount of time each slow test is allowed to run")

message("TPKG: ${TPKG_EXEC}")
add_custom_target(
"install-pkgs"
COMMAND "${TPKG_EXEC}" install
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
)

include(ProcessorCount)
ProcessorCount(NUM_CPU)

# Add a custom target 'check' that runs our unit tests.
add_custom_target(
"check"
COMMAND "${CMAKE_CTEST_COMMAND}" -j${NUM_CPU} --output-on-failure -C Debug
USES_TERMINAL
)

set(TEST_PREFIX "")
# Tests that fail locally and on toitlang/toit.
include(fail.cmake OPTIONAL)
# Tests that only fail when called with this test runner.
include(fail_pkg.cmake OPTIONAL)

message("Failing tests: ${FAILING_TESTS}")
message("Skipped tests: ${SKIP_TESTS}")

foreach(file ${TESTS})
set(test_name "/tests/${file}")
if("${test_name}" IN_LIST SKIP_TESTS)
continue()
endif()

add_test(
NAME "${test_name}"
COMMAND "${TOIT_EXEC}" "tests/${file}"
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)

if ("${file}" MATCHES "slow.toit")
set_tests_properties(${test_name} PROPERTIES TIMEOUT ${SLOW_TEST_TIMEOUT})
else()
set_tests_properties(${test_name} PROPERTIES TIMEOUT ${TEST_TIMEOUT})
endif()

if ("${test_name}" IN_LIST FAILING_TESTS)
set_tests_properties("${test_name}" PROPERTIES WILL_FAIL TRUE)
endif()

endforeach()
14 changes: 14 additions & 0 deletions tests/TESTS_LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Zero-Clause BSD License

Copyright (C) 2024 Toitware ApS

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
23 changes: 23 additions & 0 deletions tests/correct-test.toit
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (C) 2024 Toitware ApS.
// Use of this source code is governed by a Zero-Clause BSD license that can
// be found in the tests/LICENSE file.

import expect show *
import watchdog show WatchdogServiceClient

import .util

main:
run-test: |client ms system-dog| test-correct-feeding client ms system-dog

test-correct-feeding client/WatchdogServiceClient ms/int system-dog/FakeSystemWatchdog:
dog := client.create "toit.io/test/correct"
dog.start --s=1
4.repeat:
dog.feed
sleep --ms=500
dog.stop
dog.close

expect-not system-dog.failed
expect-not system-dog.reboot-initiated
28 changes: 28 additions & 0 deletions tests/many-one-failing-test.toit
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (C) 2024 Toitware ApS.
// Use of this source code is governed by a Zero-Clause BSD license that can
// be found in the tests/LICENSE file.

import expect show *
import watchdog show WatchdogServiceClient

import .util

main:
run-test: |client ms system-dog| test-many-one-timeout client ms system-dog

test-many-one-timeout client/WatchdogServiceClient ms/int system-dog/FakeSystemWatchdog:
dogs := List 20: client.create "toit.io/test/many-one-timeout/$it"
failing-dog := client.create "toit.io/test/many-one-timeout/failing"
dogs.do: it.start --s=1
failing-dog.start --s=1
4.repeat:
dogs.do: it.feed
sleep --ms=500
dogs.do: it.stop
dogs.do: it.close
failing-dog.stop
failing-dog.close

expect system-dog.failed
expect system-dog.reboot-initiated

23 changes: 23 additions & 0 deletions tests/many-test.toit
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (C) 2024 Toitware ApS.
// Use of this source code is governed by a Zero-Clause BSD license that can
// be found in the tests/LICENSE file.

import expect show *
import watchdog show WatchdogServiceClient

import .util

main:
run-test: |client ms system-dog| test-many client ms system-dog

test-many client/WatchdogServiceClient ms/int system-dog/FakeSystemWatchdog:
dogs := List 20: client.create "toit.io/test/many/$it"
dogs.do: it.start --s=1
4.repeat:
dogs.do: it.feed
sleep --ms=500
dogs.do: it.stop
dogs.do: it.close

expect-not system-dog.failed
expect-not system-dog.reboot-initiated
5 changes: 5 additions & 0 deletions tests/package.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
prefixes:
watchdog: ..
packages:
..:
path: ..
3 changes: 3 additions & 0 deletions tests/package.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dependencies:
watchdog:
path: ..
Loading