Update quickstart to rp2 blinky Change-Id: If2776ca18cf100b132a23c10f3d99c1840256441 Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/quickstart/bazel/+/228453 Lint: Lint 🤖 <android-build-ayeaye@system.gserviceaccount.com> Reviewed-by: Armando Montanez <amontanez@google.com> Commit-Queue: Taylor Cramer <cramertj@google.com>
diff --git a/.bazelignore b/.bazelignore index 912eacc..882c16b 100644 --- a/.bazelignore +++ b/.bazelignore
@@ -1 +1,12 @@ +.cipd +.presubmit +.environment +environment +node_modules +out +bazel-bin +bazel-out +bazel-pigweed +bazel-testlogs +outbazel third_party
diff --git a/.bazelrc b/.bazelrc index 293ee0d..aec79d0 100644 --- a/.bazelrc +++ b/.bazelrc
@@ -1,4 +1,4 @@ -# Copyright 2023 The Pigweed Authors +# Copyright 2024 The Pigweed Authors # # Licensed under the Apache License, Version 2.0 (the "License"); you may not # use this file except in compliance with the License. You may obtain a copy of @@ -11,35 +11,165 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations under # the License. -# -# TODO: https://pwbug.dev/258836641#comment4: Enabling bzlmod breaks the build. -common --noenable_bzlmod +# Standard Pigweed flags +# ====================== +# All Pigweed projects are expected to set these flags. They mostly pre-adopt +# future Bazel settings. +# +# The source of truth for these flags is pw_build/pigweed.bazelrc in the main +# Pigweed repo. +# # Do not attempt to configure an autodetected (local) toolchain. We vendor all # our toolchains, and CI VMs may not have any local toolchain to detect. common --repo_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1 -# Don't propagate flags or defines to the exec config. This will become the -# default one day (https://github.com/bazelbuild/bazel/issues/22457) and will -# improve cache hit rates between builds targeting different platforms. -common --experimental_exclude_defines_from_exec_config -common --experimental_exclude_starlark_flags_from_exec_config - # Required for new toolchain resolution API. build --incompatible_enable_cc_toolchain_resolution +# Expose exec toolchains for Python. +build --@rules_python//python/config_settings:exec_tools_toolchain=enabled + +# Don't propagate flags or defines to the exec config. This will become the +# default one day (https://github.com/bazelbuild/bazel/issues/22457) and will +# improve cache hit rates between builds targeting different platforms. This is +# especially impactful for large host tools like protoc, which will have its +# cache invalidated when your host C++ config changes. +common --experimental_exclude_defines_from_exec_config +common --experimental_exclude_starlark_flags_from_exec_config + +# Don't automatically create __init__.py files. +# +# This prevents spurious package name collisions at import time, and should be +# the default (https://github.com/bazelbuild/bazel/issues/7386). It's +# particularly helpful for Pigweed, because we have many potential package name +# collisions due to a profusion of stuttering paths like +# pw_transfer/py/pw_transfer. +common --incompatible_default_to_explicit_init_py + +# Don't inherit system PATH. Improves hermeticity and cache hit rates. Should +# be true by default one day (https://github.com/bazelbuild/bazel/issues/7026). +common --incompatible_strict_action_env + +# Expose exec toolchains for Python. We use these toolchains in some rule +# implementations (git grep for +# "@rules_python//python:exec_tools_toolchain_type"). +build --@rules_python//python/config_settings:exec_tools_toolchain=enabled + +# C++ toolchain configuration +# =========================== + +# Ignore all warnings in third-party code. +common --per_file_copt=external/.*@-w +common --host_per_file_copt=external/.*@-w + +# Picotool needs to build with exceptions and RTTI enabled. +common --per_file_copt=external.*picotool.*@-fexceptions,-frtti +common --host_per_file_copt=external.*picotool.*@-fexceptions,-frtti + +# Keep debugging symbols, but don't send them when flashing. +build --strip=never + +build --@pico-sdk//bazel/config:PICO_STDIO_USB=True +build --@pico-sdk//bazel/config:PICO_STDIO_UART=True + +# Sanitizer configs +# ================= +common:asan --@pigweed//pw_toolchain/host_clang:asan +common:tsan --@pigweed//pw_toolchain/host_clang:tsan +common:ubsan --@pigweed//pw_toolchain/host_clang:ubsan + +# Presubmit +# ========= # Default targets to build when running: # bazel build --config=presubmit build:presubmit -- \ //... \ - //src:echo.elf + //apps/blinky:blinky \ + //apps/blinky:rp2040_blinky.elf \ + //apps/blinky:rp2040_console \ + //apps/blinky:simulator_blinky \ + //apps/blinky:simulator_console \ + //tools:console \ -# Use the remote cache. This will only work for users who have permission to access it. +# UX settings +# =========== +# Error output settings. +common --verbose_failures +test --test_output=errors + +# Suppress the DEBUG: log messages from bazel. We get spammy DEBUG: +# messages from rules_python. +# +# TODO: https://github.com/bazelbuild/rules_python/issues/1818 - Re-enable DEBUG +# messages once rules_python stops spamming us. +common --ui_event_filters=-debug + +# Remote cache +# ============ +# Use the remote cache. This will only work for users who have permission to +# access it (including the CI system!). common:remote_cache --remote_cache=grpcs://remotebuildexecution.googleapis.com common:remote_cache --google_default_credentials=true common:remote_cache --remote_instance_name=projects/pigweed-rbe-open/instances/default-instance common:remote_cache --remote_upload_local_results=false +# Platform configuration +# ====================== +common --custom_malloc=//targets:malloc +build --@pigweed//pw_build:default_module_config=//system:module_config + +# Host platform default backends. +common --@pigweed//pw_log:backend=@pigweed//pw_log_string +common --@pigweed//pw_log:backend_impl=@pigweed//pw_log_string:impl +common --@pigweed//pw_log_string:handler_backend=@pigweed//pw_system:log_backend +common --@pigweed//pw_sys_io:backend=@pigweed//pw_sys_io_stdio +common --@pigweed//pw_system:io_backend=@pigweed//pw_system:socket_target_io + +# RP2040 platform configuration +build:rp2040 --platforms=//targets/rp2:rp2040 +build:rp2040 --//system:system=//targets/rp2:system +build:rp2040 --@pigweed//pw_assert:assert_backend=@pigweed//pw_assert_trap +build:rp2040 --@pigweed//pw_assert:assert_backend_impl=@pigweed//pw_assert_trap:impl +build:rp2040 --@pigweed//pw_assert:check_backend=@pigweed//pw_assert_trap +build:rp2040 --@pigweed//pw_assert:check_backend_impl=@pigweed//pw_assert_trap:impl +build:rp2040 --@pigweed//pw_cpu_exception:entry_backend=@pigweed//pw_cpu_exception_cortex_m:cpu_exception +build:rp2040 --@pigweed//pw_cpu_exception:entry_backend_impl=@pigweed//pw_cpu_exception_cortex_m:cpu_exception_impl +build:rp2040 --@pigweed//pw_cpu_exception:handler_backend=@pigweed//pw_cpu_exception:basic_handler +build:rp2040 --@pigweed//pw_cpu_exception:support_backend=@pigweed//pw_cpu_exception_cortex_m:support +build:rp2040 --@pigweed//pw_interrupt:backend=@pigweed//pw_interrupt_cortex_m:context +build:rp2040 --@pigweed//pw_log:backend=@pigweed//pw_log_tokenized +build:rp2040 --@pigweed//pw_log:backend_impl=@pigweed//pw_log_tokenized:impl +build:rp2040 --@pigweed//pw_log_tokenized:handler_backend=@pigweed//pw_system:log_backend +build:rp2040 --@pigweed//pw_sync:binary_semaphore_backend=@pigweed//pw_sync_freertos:binary_semaphore +build:rp2040 --@pigweed//pw_sync:interrupt_spin_lock_backend=@pigweed//pw_sync_freertos:interrupt_spin_lock +build:rp2040 --@pigweed//pw_sync:mutex_backend=@pigweed//pw_sync_freertos:mutex +build:rp2040 --@pigweed//pw_sync:thread_notification_backend=@pigweed//pw_sync_freertos:thread_notification +build:rp2040 --@pigweed//pw_sync:timed_thread_notification_backend=@pigweed//pw_sync_freertos:timed_thread_notification +build:rp2040 --@pigweed//pw_sys_io:backend=@pigweed//pw_sys_io_rp2040 +build:rp2040 --@pigweed//pw_system:device_handler_backend=@pigweed//targets/rp2040:device_handler +build:rp2040 --@pigweed//pw_system:extra_platform_libs=//targets/rp2:extra_platform_libs +build:rp2040 --@pigweed//pw_system:io_backend=@pigweed//pw_system:sys_io_target_io +build:rp2040 --@pigweed//pw_thread_freertos:config_override=//targets/rp2:thread_config_overrides +build:rp2040 --@pigweed//pw_thread:id_backend=@pigweed//pw_thread_freertos:id +build:rp2040 --@pigweed//pw_thread:iteration_backend=@pigweed//pw_thread_freertos:thread_iteration +build:rp2040 --@pigweed//pw_thread:sleep_backend=@pigweed//pw_thread_freertos:sleep +build:rp2040 --@pigweed//pw_thread:thread_backend=@pigweed//pw_thread_freertos:thread +build:rp2040 --@pigweed//pw_thread:test_thread_context_backend=@pigweed//pw_thread_freertos:test_thread_context +build:rp2040 --@pigweed//pw_unit_test:config_override=//targets/rp2:64k_unit_tests +build:rp2040 --@pigweed//pw_unit_test:main=//targets/rp2:unit_test_rpc_main +build:rp2040 --@freertos//:freertos_config=//targets/rp2:freertos_config +build:rp2040 --@pico-sdk//bazel/config:PICO_STDIO_USB=True +build:rp2040 --@pico-sdk//bazel/config:PICO_STDIO_UART=True +build:rp2040 --@pico-sdk//bazel/config:PICO_CLIB=llvm_libc +build:rp2040 --@pico-sdk//bazel/config:PICO_TOOLCHAIN=clang +build:rp2040 --@pigweed//pw_toolchain:cortex-m_toolchain_kind=clang +test:rp2040 --run_under=@pigweed//targets/rp2040/py:unit_test_client + +# RP2350 is the same as rp2040 but with a different --platforms setting. +build:rp2350 --config=rp2040 +build:rp2350 --platforms=//targets/rp2:rp2350 + # User bazelrc file; see # https://bazel.build/configure/best-practices#bazelrc-file #
diff --git a/.bazelversion b/.bazelversion index d6139c1..e44dad1 100644 --- a/.bazelversion +++ b/.bazelversion
@@ -1 +1 @@ -8.0.0-pre.20240618.2 +0ddcfd327ffd012d348deeae08ec0836409706ad
diff --git a/.buildifier.json b/.buildifier.json new file mode 100644 index 0000000..d0ffbbe --- /dev/null +++ b/.buildifier.json
@@ -0,0 +1,8 @@ +{ + "type": "auto", + "warningsList": [ + "load", + "native-build", + "unsorted-dict-items" + ] +}
diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..7f63e9b --- /dev/null +++ b/.clang-format
@@ -0,0 +1,8 @@ +BasedOnStyle: Google +BinPackArguments: false +BinPackParameters: false +DerivePointerAlignment: false +PointerAlignment: Left +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +LineEnding: LF
diff --git a/.clangd.shared b/.clangd.shared new file mode 100644 index 0000000..ef516ad --- /dev/null +++ b/.clangd.shared
@@ -0,0 +1,2 @@ +CompileFlags: + Add: -ferror-limit=0
diff --git a/.github/workflows/postsubmit.yaml b/.github/workflows/postsubmit.yaml index 0edaf94..d7f571c 100644 --- a/.github/workflows/postsubmit.yaml +++ b/.github/workflows/postsubmit.yaml
@@ -22,7 +22,15 @@ disk-cache: ${{ github.workflow }} # Share repository cache between workflows. repository-cache: true - - name: Bazel Build - run: bazel build ... - - name: Bazel Test - run: bazel test ... + - name: Presubmit + run: bazel build --config=presubmit + - name: RP2040 + run: bazel build --config=rp2040 //... + - name: Test + run: bazel test //... + - name: ASAN + run: bazel test --config=asan //... + - name: TSAN + run: bazel test --config=tsan //... + - name: UBSAN + run: bazel test --config=ubsan //...
diff --git a/.github/workflows/presubmit.yaml b/.github/workflows/presubmit.yaml index e9aa5c0..28e6d7e 100644 --- a/.github/workflows/presubmit.yaml +++ b/.github/workflows/presubmit.yaml
@@ -23,7 +23,15 @@ disk-cache: ${{ github.workflow }} # Share repository cache between workflows. repository-cache: true - - name: Bazel Build - run: bazel build ... - - name: Bazel Test - run: bazel test ... + - name: Presubmit + run: bazel build --config=presubmit + - name: RP2040 + run: bazel build --config=rp2040 //... + - name: Test + run: bazel test //... + - name: ASAN + run: bazel test --config=asan //... + - name: TSAN + run: bazel test --config=tsan //... + - name: UBSAN + run: bazel test --config=ubsan //...
diff --git a/.gitignore b/.gitignore index 13fa984..2cd1c37 100644 --- a/.gitignore +++ b/.gitignore
@@ -1,6 +1,64 @@ +# Build +out/ +.presubmit/ +compile_commands.json user.bazelrc -bazel-* +/bazel-* -# Editor files -*.swo +# Ignore until https://github.com/bazelbuild/bazel/issues/20369 is fixed. +MODULE.bazel.lock + +# Environment +.environment/ +environment/ +build_overrides/pigweed_environment.gni + +# Editors +.pw_ide/ +.vscode/settings.json +.vscode/tasks.json +.vscode/pw_user_*.json +.vscode/*.bak.json +.idea/ +.project +.cproject +.clangd +.clangd/ *.swp +*.swo +.#* + +# Python +python*-env/ +.python*-env/ +venv/ +*.pyc +*.egg/ +*.eggs/ +*.egg-info/ +.cache/ +.mypy_cache/ +__pycache__/ + +# Mac +.DS_Store + +# GDB +.gdb_history + +# Git +*.orig +*.BACKUP.* +*.BASE.* +*.LOCAL.* +*.REMOTE.* +*_BACKUP_*.txt +*_BASE_*.txt +*_LOCAL_*.txt +*_REMOTE_*.txt + +# Other +logfile.txt +pw_console-*logs.txt +.pw_console.user.yaml +factory-logs-*.txt
diff --git a/.pw_console.yaml b/.pw_console.yaml new file mode 100644 index 0000000..4870700 --- /dev/null +++ b/.pw_console.yaml
@@ -0,0 +1,99 @@ +# This is a pw_console config file that defines a default window layout. +# For more info on what can be added to this file see: +# https://pigweed.dev/pw_console/py/pw_console/docs/user_guide.html#configuration +config_title: pw_console + +# Window layout +windows: + # Left split with tabbed views. + Split 1 tabbed: + Python Repl: + hidden: False + # Right split with stacked views. + Split 2 stacked: + Device Logs: + hidden: False + Host Logs: + hidden: False + +window_column_split_method: vertical +# window_column_split_method: horizontal + +# Default colors: +ui_theme: dark +code_theme: pigweed-code +swap_light_and_dark: False + +# A few other choices: +# ui_theme: high-contrast-dark +# ui_theme: nord +# ui_theme: synthwave84 +# code_theme: gruvbox-dark +# code_theme: pigweed-code-light +# code_theme: synthwave84 + +# Log display options: +spaces_between_columns: 2 +hide_date_from_log_time: True +recolor_log_lines_to_match_level: False + +column_order: + # Column name + - time + - level + - timestamp + - module + # Hidden: + # - source_name + +column_order_omit_unspecified_columns: True + +snippets: + Echo RPC: + code: | + device.rpcs.pw.rpc.EchoService.Echo(msg='hello world') + description: | + Send a string to the device and receive a response with the same + message back. + + >>> device.rpcs.pw.rpc.EchoService.Echo(msg='hello world') + (Status.OK, pw.rpc.EchoMessage(msg='hello world')) + + Reboot to bootloader: + code: | + device.rpcs.board.Board.Reboot(reboot_type=1) + description: | + Sent a reboot request to the device. The console must be + relaunched to reconnect. + + Get onboard temp sensor value: + code: | + device.rpcs.board.Board.OnboardTemp() + description: | + Get the current value of the onboard temperature sensor. + + ```pycon + >>> device.rpcs.board.Board.OnboardTemp() + (Status.OK, board.OnboardTempResponse(temp=24.797744750976562)) + ``` + + Log onboard temp sensor values every 1000ms: + code: | + call = device.rpcs.board.Board.OnboardTempStream.invoke( + request_args=dict(sample_interval_ms=1000), + on_next=lambda _, message: LOG.info(message) + ) + description: | + Start logging with: + + ```pycon + >>> call = device.rpcs.board.Board.OnboardTempStream.invoke(request_args=dict(sample_interval_ms=1000), on_next=lambda _, message: LOG.info(message)) + ``` + + Log messages will appear in the 'Host Logs' window. + To stop the streaming RPC run `call.cancel()`: + + ```pycon + >>> call.cancel() + True + ```
diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..bf6ac5c --- /dev/null +++ b/.vscode/extensions.json
@@ -0,0 +1,9 @@ +{ + "recommendations": [ + "pigweed.pigweed" + ], + "unwantedRecommendations": [ + "ms-vscode.cpptools", + "ms-vscode.cpptools-extension-pack" + ] +}
diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..b13fcec --- /dev/null +++ b/AUTHORS
@@ -0,0 +1,7 @@ +# This is the list of Pigweed authors for copyright purposes. +# +# This does not necessarily list everyone who has contributed code, since in +# some cases, their employer may be the copyright holder. To see the full list +# of contributors, see the revision history in source control. + +Google LLC
diff --git a/BUILD.bazel b/BUILD.bazel index 1767ea4..6ddb18f 100644 --- a/BUILD.bazel +++ b/BUILD.bazel
@@ -1,4 +1,4 @@ -# Copyright 2023 The Pigweed Authors +# Copyright 2024 The Pigweed Authors # # Licensed under the Apache License, Version 2.0 (the "License"); you may not # use this file except in compliance with the License. You may obtain a copy of @@ -11,11 +11,42 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations under # the License. -load("@rules_python//python:pip.bzl", "compile_pip_requirements") -# Run bazel run //:pip_requirements.update to regenerate requirements_lock.txt. -compile_pip_requirements( - name = "pip_requirements", - requirements_in = "requirements.in", - requirements_txt = "requirements_lock.txt", +load("@bazel_skylib//rules:copy_file.bzl", "copy_file") +load("@hedron_compile_commands//:refresh_compile_commands.bzl", "refresh_compile_commands") +load("@pigweed//pw_build:compatibility.bzl", "incompatible_with_mcu") + +package(default_visibility = ["//visibility:public"]) + +copy_file( + name = "copy_clangd", + src = "@pigweed//pw_toolchain/host_clang:clangd", + out = "clangd", + allow_symlink = True, +) + +refresh_compile_commands( + name = "refresh_compile_commands", + out_dir = ".compile_commands", + target_compatible_with = incompatible_with_mcu(), + target_groups = { + "host_simulator": [ + "//apps/blinky:simulator_blinky", + "//modules/blinky:blinky_test", + ], + "rp2040": [ + "//apps/blinky:rp2040_blinky.elf", + [ + "//modules/blinky:blinky_test", + "--config=rp2040", + ], + ], + }, +) + +filegroup( + name = "pw_console_config", + srcs = [ + ".pw_console.yaml", + ], )
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..677be08 --- /dev/null +++ b/CONTRIBUTING.md
@@ -0,0 +1,29 @@ +# Contributing to Pigweed + +Pigweed lets anyone contribute to the project, regardless of their employer. +The Pigweed project reviews and encourages well-tested, high-quality +contributions from anyone who wants to contribute to Pigweed. + +## Contributor License Agreement + +Contributions to this project must be accompanied by a Contributor License +Agreement (CLA). + +To see any Contributor License Agreements on file or to sign a CLA, go to +<https://cla.developers.google.com/>. + +For more information about the Google CLA, see +[Contributor License Agreements](https://cla.developers.google.com/about). + +## Contributing changes and submitting code reviews + +All changes require review, including changes by project members. + +For detailed instructions on how to contribute changes, +see [the Gerrit docs](https://gerrit-review.googlesource.com/Documentation/intro-user.html). + +## Community guidelines + +This project observes the following community guidelines: + + * [Google's Open Source Community Guidelines](https://opensource.google/conduct/)
diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 0000000..22367e6 --- /dev/null +++ b/MODULE.bazel
@@ -0,0 +1,81 @@ +# Copyright 2024 The Pigweed Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +module( + name = "quickstart", +) + +bazel_dep(name = "bazel_skylib", version = "1.7.1") +bazel_dep(name = "freertos", version = "10.5.1.bcr.2") +bazel_dep(name = "nanopb", repo_name = "com_github_nanopb_nanopb") +bazel_dep(name = "pico-sdk", version = "2.0.0") +bazel_dep(name = "pigweed") +bazel_dep(name = "platforms", version = "0.0.10") +bazel_dep(name = "pw_toolchain") +bazel_dep(name = "rules_cc") +bazel_dep(name = "rules_python", version = "0.34.0") + +bazel_dep(name = "hedron_compile_commands", dev_dependency = True) + +# Module overrides +# ================ +# TODO: https://pwbug.dev/349880767 - Point this back to the upstream repo once +# this PR is merged. +archive_override( + module_name = "hedron_compile_commands", + strip_prefix = "bazel-compile-commands-extractor-163521345aa6366fd1ed801b989b668b5c806f69", + urls = ["https://github.com/chadnorvell/bazel-compile-commands-extractor/archive/163521345aa6366fd1ed801b989b668b5c806f69.tar.gz"], +) + +# TODO: https://pwbug.dev/354274498 - nanopb is not yet in the BCR. +git_override( + module_name = "nanopb", + commit = "7c6c581bc6f7406a4f01c3b9853251ff0a68458b", + remote = "https://github.com/nanopb/nanopb.git", +) + +git_override( + module_name = "pigweed", + # ROLL: Warning: this entry is automatically updated. + # ROLL: Last updated 2024-08-07. + # ROLL: By https://cr-buildbucket.appspot.com/build/8740243540358493793. + commit = "146fd4b5c55fb45c390515b9d5faa2f5abd00be2", + remote = "https://pigweed.googlesource.com/pigweed/pigweed", +) + +git_override( + module_name = "pw_toolchain", + # ROLL: Warning: this entry is automatically updated. + # ROLL: Last updated 2024-08-07. + # ROLL: By https://cr-buildbucket.appspot.com/build/8740243540358493793. + commit = "146fd4b5c55fb45c390515b9d5faa2f5abd00be2", + remote = "https://pigweed.googlesource.com/pigweed/pigweed", + strip_prefix = "pw_toolchain_bazel", +) + +# TODO: https://pwbug.dev/258836641 - Pre-release version needed for the Pico +# SDK. Remove this once rules_cc 0.10.0 is released and the Pico SDK +# MODULE.bazel declares its dependency on it. +archive_override( + module_name = "rules_cc", + integrity = "sha256-NddP6xi6LzsIHT8bMSVJ2NtoURbN+l3xpjvmIgB6aSg=", + strip_prefix = "rules_cc-1acf5213b6170f1f0133e273cb85ede0e732048f", + urls = [ + "https://github.com/bazelbuild/rules_cc/archive/1acf5213b6170f1f0133e273cb85ede0e732048f.zip", + ], +) + +http_archive = use_repo_rule( + "@bazel_tools//tools/build_defs/repo:http.bzl", + "http_archive", +)
diff --git a/OWNERS b/OWNERS new file mode 100644 index 0000000..528c611 --- /dev/null +++ b/OWNERS
@@ -0,0 +1,7 @@ +# Remove the `*` from this file and add specific owners to this file and to +# subdirectories where appropriate to enforce OWNERS approval in this +# repository. +# +# Syntax for OWNERS files can be found at: +# https://pigweed-review.googlesource.com/plugins/code-owners/Documentation/backend-find-owners.html#syntax +*
diff --git a/README.md b/README.md index 7da4f53..21acbde 100644 --- a/README.md +++ b/README.md
@@ -1,59 +1,67 @@ # Pigweed: minimal Bazel example This repository contains a minimal example of a Bazel-based Pigweed project. -It's an echo application for the STM32F429 Discovery Board. +It is a LED-blinking service (featuring RPC control!) for the +[Raspberry Pi Pico](https://www.raspberrypi.com/products/raspberry-pi-pico/). +It can also be run on any computer using the included simulator. -## Cloning +## Getting the code ``` -git clone --recursive https://pigweed.googlesource.com/pigweed/quickstart/bazel +git clone https://pigweed.googlesource.com/pigweed/quickstart/bazel pw_bazel_quickstart +cd pw_bazel_quickstart ``` -If you already cloned but forgot to include `--recursive`, run `git submodule -update --init` to pull all submodules. +## Dependencies -TODO: b/300695111 - Don't require submodules for this example. +The only dependency that must be installed is Bazelisk. -## Building +Bazelisk is a launcher for the Bazel build system that allows for easy +management of multiple Bazel versions. -We'll assume you already have Bazel on your system. If you don't, the -recommended way to get it is through -[Bazelisk](https://github.com/bazelbuild/bazelisk/blob/master/README.md). +[Instructions for installing Bazelisk can be found here.](https://github.com/bazelbuild/bazelisk/blob/master/README.md) -To build the entire project (including building the application for both the -host and the STM32 Discovery Board), run +## Running on the simulator + +To run the simulator, type: +`bazelisk run //apps/blinky:simulator_blinky` +Then, in a new console, connect to the simulator using: +`bazelisk run //apps/blinky:simulator_console` + +## Running on hardware + +To start, connect a Raspberry Pi Pico, Pico 2, or debug probe via USB. + +To run on the Raspberry Pi Pico, type: +`bazelisk run //apps/blinky:flash_rp2040` +Then, in a new console, connect to the device using: +`bazelisk run //apps/blinky:rp2040_console` + +## Controlling the LED + +Once connected with a console, RPCs can be sent to control the LED. +Try running: ``` -bazel build //... +device.set_led(True) +device.set_led(False) +device.toggle_led() +device.blink(blink_count=3) ``` -To run the application locally on your machine, run, +## Running unit tests on the host device -``` -bazel run //src:echo -``` +`bazelisk test //...` will run the unit tests defined in this project, +such as the ones in `modules/blinky/blinky_test.cc`. -## Flashing +## Running unit tests on hardware -To flash the firmware to a STM32F429 Discovery Board connected to your machine, -run, +`bazelisk run @pigweed//targets/rp2040/py:unit_test_server` in one console followed by +`bazelisk test //... --config=rp2040` will also allow running the unit tests on-device. -``` -bazel run //tools:flash -``` +## Next steps -Note that you _don't need to build the firmware first_: Bazel knows that the -firmware images are needed to flash the board, and will build them for you. And -if you edit the source of the firmware or any of its dependencies, it will get -rebuilt when you flash. - -## Communicating - -Run, - -``` -bazel run //tools:miniterm -- /dev/ttyACM0 --filter=debug -``` - -to communicate with the board. When you transmit a character, you should get -the same character back! +Try poking around the codebase for inspiration about how Pigweed projects can be +organized. Most of the relevant code in this quickstart (including RPC +definitions) is inside `modules/blinky`, with some client-side Python code in +`tools/console.py`.
diff --git a/WORKSPACE b/WORKSPACE deleted file mode 100644 index 38523cb..0000000 --- a/WORKSPACE +++ /dev/null
@@ -1,143 +0,0 @@ -# Copyright 2023 The Pigweed Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. - -load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") - -# Load Pigweed's own dependencies that we'll need. -# -# TODO: b/274148833 - Don't require users to spell these out. -http_archive( - name = "platforms", - sha256 = "8150406605389ececb6da07cbcb509d5637a3ab9a24bc69b1101531367d89d74", - urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/platforms/releases/download/0.0.8/platforms-0.0.8.tar.gz", - "https://github.com/bazelbuild/platforms/releases/download/0.0.8/platforms-0.0.8.tar.gz", - ], -) - -http_archive( - name = "bazel_skylib", # 2022-09-01 - sha256 = "4756ab3ec46d94d99e5ed685d2d24aece484015e45af303eb3a11cab3cdc2e71", - strip_prefix = "bazel-skylib-1.3.0", - urls = ["https://github.com/bazelbuild/bazel-skylib/archive/refs/tags/1.3.0.zip"], -) - -http_archive( - name = "rules_proto", - sha256 = "dc3fb206a2cb3441b485eb1e423165b231235a1ea9b031b4433cf7bc1fa460dd", - strip_prefix = "rules_proto-5.3.0-21.7", - urls = [ - "https://github.com/bazelbuild/rules_proto/archive/refs/tags/5.3.0-21.7.tar.gz", - ], -) - -http_archive( - name = "rules_python", - sha256 = "0a8003b044294d7840ac7d9d73eef05d6ceb682d7516781a4ec62eeb34702578", - strip_prefix = "rules_python-0.24.0", - url = "https://github.com/bazelbuild/rules_python/releases/download/0.24.0/rules_python-0.24.0.tar.gz", -) - -load("@rules_python//python:repositories.bzl", "py_repositories") - -py_repositories() - -http_archive( - name = "com_google_protobuf", - sha256 = "c6003e1d2e7fefa78a3039f19f383b4f3a61e81be8c19356f85b6461998ad3db", - strip_prefix = "protobuf-3.17.3", - url = "https://github.com/protocolbuffers/protobuf/archive/v3.17.3.tar.gz", -) - -load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") - -protobuf_deps() - -# TODO(b/311746469): Switch back to a released version when possible. -git_repository( - name = "rules_fuzzing", - commit = "67ba0264c46c173a75825f2ae0a0b4b9b17c5e59", - remote = "https://github.com/bazelbuild/rules_fuzzing", -) - -load("@rules_fuzzing//fuzzing:repositories.bzl", "rules_fuzzing_dependencies") - -rules_fuzzing_dependencies() - -load("@rules_fuzzing//fuzzing:init.bzl", "rules_fuzzing_init") - -rules_fuzzing_init() - -git_repository( - name = "pigweed", - # ROLL: Warning: this entry is automatically updated. - # ROLL: Last updated 2024-08-07. - # ROLL: By https://cr-buildbucket.appspot.com/build/8740220870553192513. - commit = "04109d522e8b54b140d5d6dca2aa2171e4b5e22d", - remote = "https://pigweed.googlesource.com/pigweed/pigweed.git", -) - -git_repository( - name = "pw_toolchain", - # ROLL: Warning: this entry is automatically updated. - # ROLL: Last updated 2024-08-07. - # ROLL: By https://cr-buildbucket.appspot.com/build/8740220870553192513. - commit = "04109d522e8b54b140d5d6dca2aa2171e4b5e22d", - remote = "https://pigweed.googlesource.com/pigweed/pigweed.git", - strip_prefix = "pw_toolchain_bazel", -) - -# Get ready to grab CIPD dependencies. For this minimal example, the only -# dependencies will be the toolchains and OpenOCD (used for flashing). -load( - "@pigweed//pw_env_setup/bazel/cipd_setup:cipd_rules.bzl", - "cipd_client_repository", - "cipd_repository", -) - -cipd_client_repository() - - -load("@pigweed//pw_toolchain:register_toolchains.bzl", "register_pigweed_cxx_toolchains") - -register_pigweed_cxx_toolchains() - -# Get the OpenOCD binary (we'll use it for flashing). -cipd_repository( - name = "openocd", - path = "infra/3pp/tools/openocd/${os}-${arch}", - tag = "version:2@0.11.0-3", -) - -load("@rules_python//python:repositories.bzl", "python_register_toolchains") - -# Set up the Python interpreter and PyPI dependencies we'll need. -python_register_toolchains( - name = "python3", - python_version = "3.11", -) - -load("@python3//:defs.bzl", "interpreter") -load("@rules_python//python:pip.bzl", "pip_parse") - -pip_parse( - name = "pypi", - python_interpreter_target = interpreter, - requirements_lock = "//:requirements_lock.txt", -) - -load("@pypi//:requirements.bzl", "install_deps") - -install_deps()
diff --git a/apps/blinky/BUILD.bazel b/apps/blinky/BUILD.bazel new file mode 100644 index 0000000..0cec3ed --- /dev/null +++ b/apps/blinky/BUILD.bazel
@@ -0,0 +1,99 @@ +# Copyright 2024 The Pigweed Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +load("@pigweed//targets/host_device_simulator:transition.bzl", "host_device_simulator_binary") +load("@pigweed//targets/rp2040:flash.bzl", "flash_rp2040") +load("//targets/rp2:binary.bzl", "rp2040_binary", "rp2350_binary") +load("//tools:tools.bzl", "device_console", "host_console") + +package(default_visibility = ["//visibility:public"]) + +cc_binary( + name = "blinky", + srcs = ["main.cc"], + deps = [ + "//modules/blinky:service", + "//system", + "@pigweed//pw_log", + "@pigweed//pw_system:async", + + # These should be provided by pw_system:async. + "@pigweed//pw_assert:assert_backend_impl", + "@pigweed//pw_assert:check_backend_impl", + "@pigweed//pw_log:backend_impl", + "@pigweed//pw_system:extra_platform_libs", + ], +) + +# Create an rp2040 flashable ELF +rp2040_binary( + name = "rp2040_blinky.elf", + binary = ":blinky", +) + +# Create an rp2350 flashable ELF +rp2350_binary( + name = "rp2350_blinky.elf", + binary = ":blinky", +) + +# Create a host binary using the Pigweed upstream pw_system host_device_simulator. +host_device_simulator_binary( + name = "simulator_blinky", + binary = ":blinky", +) + +host_console( + name = "simulator_console", + binary = ":simulator_blinky", +) + +host_console( + name = "simulator_webconsole", + binary = ":simulator_blinky", + extra_args = ["--browser"], +) + +device_console( + name = "rp2040_console", + binary = ":rp2040_blinky.elf", +) + +device_console( + name = "rp2040_webconsole", + binary = ":rp2040_blinky.elf", + extra_args = ["--browser"], +) + +device_console( + name = "rp2350_console", + binary = ":rp2350_blinky.elf", +) + +device_console( + name = "rp2350_webconsole", + binary = ":rp2350_blinky.elf", + extra_args = ["--browser"], +) + +flash_rp2040( + name = "flash_rp2040", + rp2040_binary = "rp2040_blinky.elf", +) + +# Note: Despite the name, the rule works for the 2350. +flash_rp2040( + name = "flash_rp2350", + rp2040_binary = "rp2350_blinky.elf", +)
diff --git a/apps/blinky/main.cc b/apps/blinky/main.cc new file mode 100644 index 0000000..3032d43 --- /dev/null +++ b/apps/blinky/main.cc
@@ -0,0 +1,34 @@ +// Copyright 2024 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +#define PW_LOG_MODULE_NAME "MAIN" + +#include "modules/blinky/service.h" +#include "pw_log/log.h" +#include "pw_system/system.h" +#include "system/system.h" + +int main() { + demo::system::Init(); + auto& rpc_server = pw::System().rpc_server(); + auto& monochrome_led = demo::system::MonochromeLed(); + + static demo::BlinkyService blinky_service; + blinky_service.Init( + pw::System().dispatcher(), pw::System().allocator(), monochrome_led); + rpc_server.RegisterService(blinky_service); + + PW_LOG_INFO("Started blinky app; waiting for RPCs..."); + demo::system::Start(); + PW_UNREACHABLE; +}
diff --git a/echo.bzl b/echo.bzl deleted file mode 100644 index 4151508..0000000 --- a/echo.bzl +++ /dev/null
@@ -1,64 +0,0 @@ -# Copyright 2023 The Pigweed Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. -"""Build rules and transitions for firmware.""" - -def _stm32_transition_impl(settings, attr): - # buildifier: disable=unused-variable - _ignore = attr - return { - "//command_line_option:platforms": "//targets:stm32", - "@pigweed//pw_boot:backend": "@pigweed//pw_boot_cortex_m", - "@pigweed//pw_assert:backend": "@pigweed//pw_assert_basic", - "@pigweed//pw_assert:backend_impl": "@pigweed//pw_assert_basic:impl", - "@pigweed//pw_assert:check_backend": "@pigweed//pw_assert_basic", - "@pigweed//pw_assert:check_backend_impl": "@pigweed//pw_assert_basic:impl", - "@pigweed//pw_log:backend": "@pigweed//pw_log_basic", - "@pigweed//pw_log:backend_impl": "@pigweed//pw_log_basic:impl", - "@pigweed//pw_sys_io:backend": "@pigweed//pw_sys_io_baremetal_stm32f429", - } - -_stm32_transition = transition( - implementation = _stm32_transition_impl, - inputs = [], - outputs = [ - "//command_line_option:platforms", - "@pigweed//pw_boot:backend", - "@pigweed//pw_assert:backend", - "@pigweed//pw_assert:backend_impl", - "@pigweed//pw_assert:check_backend", - "@pigweed//pw_assert:check_backend_impl", - "@pigweed//pw_log:backend", - "@pigweed//pw_log:backend_impl", - "@pigweed//pw_sys_io:backend", - ], -) - -def _binary_impl(ctx): - out = ctx.actions.declare_file(ctx.label.name) - ctx.actions.symlink(output = out, target_file = ctx.executable.binary) - return [DefaultInfo(files = depset([out]), executable = out)] - -# TODO(tpudlik): Replace this with platform_data when it is available. -stm32_cc_binary = rule( - _binary_impl, - attrs = { - "binary": attr.label( - doc = "cc_binary to build for stm32", - cfg = _stm32_transition, - executable = True, - mandatory = True, - ), - "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), - }, -)
diff --git a/modules/blinky/BUILD.bazel b/modules/blinky/BUILD.bazel new file mode 100644 index 0000000..967b44d --- /dev/null +++ b/modules/blinky/BUILD.bazel
@@ -0,0 +1,97 @@ +# Copyright 2024 The Pigweed Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +load("@pigweed//pw_build:pigweed.bzl", "pw_cc_test") +load( + "@pigweed//pw_protobuf_compiler:pw_proto_library.bzl", + "nanopb_proto_library", + "nanopb_rpc_proto_library", +) +load("@rules_python//python:proto.bzl", "py_proto_library") + +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "blinky", + srcs = ["blinky.cc"], + hdrs = ["blinky.h"], + implementation_deps = [ + "@pigweed//pw_log", + "@pigweed//pw_preprocessor", + ], + deps = [ + "//modules/timer_future", + "//system", + "@pigweed//pw_async2:coro", + "@pigweed//pw_async2:coro_or_else_task", + "@pigweed//pw_async2:dispatcher", + "@pigweed//pw_chrono:system_clock", + "@pigweed//pw_function", + "@pigweed//pw_sync:interrupt_spin_lock", + "@pigweed//pw_sync:lock_annotations", + "@pigweed//pw_system:async", + ], +) + +pw_cc_test( + name = "blinky_test", + srcs = ["blinky_test.cc"], + deps = [ + ":blinky", + "@pigweed//pw_allocator:testing", + "@pigweed//pw_async2:dispatcher", + "@pigweed//pw_digital_io:digital_io_mock", + "@pigweed//pw_thread:sleep", + "@pigweed//pw_unit_test", + ], +) + +cc_library( + name = "service", + srcs = ["service.cc"], + hdrs = ["service.h"], + deps = [ + ":blinky", + ":nanopb_rpc", + "@pigweed//pw_allocator:allocator", + "@pigweed//pw_assert:check", + "@pigweed//pw_async2:dispatcher", + ], +) + +proto_library( + name = "proto", + srcs = ["blinky.proto"], + import_prefix = "blinky_pb", + strip_import_prefix = "/modules/blinky", + deps = [ + "@pigweed//pw_protobuf:common_proto", + ], +) + +nanopb_proto_library( + name = "nanopb", + deps = [":proto"], +) + +nanopb_rpc_proto_library( + name = "nanopb_rpc", + nanopb_proto_library_deps = [":nanopb"], + deps = [":proto"], +) + +py_proto_library( + name = "py_pb2", + deps = [":proto"], +)
diff --git a/modules/blinky/blinky.cc b/modules/blinky/blinky.cc new file mode 100644 index 0000000..72954c7 --- /dev/null +++ b/modules/blinky/blinky.cc
@@ -0,0 +1,142 @@ +// Copyright 2024 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +#define PW_LOG_MODULE_NAME "BLINKY" +#include "blinky.h" + +#include <mutex> + +#include "modules/blinky/blinky.h" +#include "pw_async2/coro.h" +#include "pw_log/log.h" + +namespace demo { + +using ::pw::Allocator; +using ::pw::OkStatus; +using ::pw::Status; +using ::pw::async2::Coro; +using ::pw::async2::CoroContext; +using ::pw::async2::Dispatcher; +using ::pw::digital_io::DigitalInOut; +using ::pw::digital_io::State; + +namespace { + +bool IsOn(DigitalInOut& io) { + auto result = io.GetState(); + if (!result.ok()) { + return false; + } + return *result == State::kActive; +} + +void TurnOn(DigitalInOut& io) { io.SetState(State::kActive).IgnoreError(); } + +void TurnOff(DigitalInOut& io) { io.SetState(State::kInactive).IgnoreError(); } + +void ToggleIo(DigitalInOut& io) { + io.SetState(IsOn(io) ? State::kInactive : State::kActive).IgnoreError(); +} + +} // namespace + +Coro<Status> Blinky::BlinkLoop(CoroContext&, + uint32_t blink_count, + pw::chrono::SystemClock::duration interval) { + for (uint32_t blinked = 0; blinked < blink_count || blink_count == 0; + ++blinked) { + { + PW_LOG_INFO("LED blinking: OFF"); + std::lock_guard lock(lock_); + TurnOff(*monochrome_led_); + } + co_await timer_.WaitFor(interval); + { + PW_LOG_INFO("LED blinking: ON"); + std::lock_guard lock(lock_); + TurnOn(*monochrome_led_); + } + co_await timer_.WaitFor(interval); + } + { + std::lock_guard lock(lock_); + TurnOff(*monochrome_led_); + } + PW_LOG_INFO("Stopped blinking"); + co_return OkStatus(); +} + +Blinky::Blinky() + : blink_task_(Coro<Status>::Empty(), [](Status) { + PW_LOG_ERROR("Failed to allocate blink loop coroutine."); + }) {} + +void Blinky::Init(Dispatcher& dispatcher, + Allocator& allocator, + pw::digital_io::DigitalInOut& monochrome_led) { + dispatcher_ = &dispatcher; + allocator_ = &allocator; + + std::lock_guard lock(lock_); + monochrome_led_ = &monochrome_led; + monochrome_led_->Enable().IgnoreError(); + TurnOff(*monochrome_led_); +} + +Blinky::~Blinky() { blink_task_.Deregister(); } + +void Blinky::Toggle() { + blink_task_.Deregister(); + PW_LOG_INFO("Toggling LED"); + std::lock_guard lock(lock_); + ToggleIo(*monochrome_led_); +} + +void Blinky::SetLed(bool on) { + blink_task_.Deregister(); + std::lock_guard lock(lock_); + if (on) { + PW_LOG_INFO("Setting LED on"); + TurnOn(*monochrome_led_); + } else { + PW_LOG_INFO("Setting LED off"); + TurnOff(*monochrome_led_); + } +} + +pw::Status Blinky::Blink(uint32_t blink_count, uint32_t interval_ms) { + if (blink_count == 0) { + PW_LOG_INFO("Blinking forever at a %ums interval", interval_ms); + } else { + PW_LOG_INFO( + "Blinking %u times at a %ums interval", blink_count, interval_ms); + } + + pw::chrono::SystemClock::duration interval = + pw::chrono::SystemClock::for_at_least( + std::chrono::milliseconds(interval_ms)); + + blink_task_.Deregister(); + CoroContext coro_cx(*allocator_); + blink_task_.SetCoro(BlinkLoop(coro_cx, blink_count, interval)); + dispatcher_->Post(blink_task_); + return OkStatus(); +} + +bool Blinky::IsIdle() const { + std::lock_guard lock(lock_); + return !blink_task_.IsRegistered(); +} + +} // namespace demo
diff --git a/modules/blinky/blinky.h b/modules/blinky/blinky.h new file mode 100644 index 0000000..33d0a97 --- /dev/null +++ b/modules/blinky/blinky.h
@@ -0,0 +1,79 @@ +// Copyright 2024 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +#pragma once + +#include <chrono> + +#include "modules/timer_future/timer_future.h" +#include "pw_allocator/allocator.h" +#include "pw_async2/coro_or_else_task.h" +#include "pw_async2/dispatcher.h" +#include "pw_chrono/system_clock.h" +#include "pw_digital_io/digital_io.h" +#include "pw_status/status.h" +#include "pw_sync/interrupt_spin_lock.h" +#include "pw_sync/lock_annotations.h" + +namespace demo { + +/// Simple component that blinks the on-board LED. +class Blinky final { + public: + static constexpr uint32_t kDefaultIntervalMs = 1000; + static constexpr pw::chrono::SystemClock::duration kDefaultInterval = + pw::chrono::SystemClock::for_at_least( + std::chrono::milliseconds(kDefaultIntervalMs)); + + Blinky(); + ~Blinky(); + + /// Injects this object's dependencies. + /// + /// This method MUST be called before using any other method. + void Init(pw::async2::Dispatcher& dispatcher, + pw::Allocator& allocator, + pw::digital_io::DigitalInOut& monochrome_led); + + /// Turns the LED on if it is off, and off if it is on. + void Toggle() PW_LOCKS_EXCLUDED(lock_); + + /// Sets the state of the LED. + void SetLed(bool on) PW_LOCKS_EXCLUDED(lock_); + + /// Queues a sequence of call backs to blink the configured number of times. + /// + /// @param blink_count The number of times to blink the LED. + /// @param interval_ms The duration of a blink, in milliseconds. + pw::Status Blink(uint32_t blink_count, uint32_t interval_ms) + PW_LOCKS_EXCLUDED(lock_); + + /// Returns whether this instance is currently blinking or not. + bool IsIdle() const PW_LOCKS_EXCLUDED(lock_); + + private: + /// Creates a blinking coroutine. + pw::async2::Coro<pw::Status> BlinkLoop( + pw::async2::CoroContext&, + uint32_t blink_count, + pw::chrono::SystemClock::duration interval) PW_LOCKS_EXCLUDED(lock_); + + pw::async2::Dispatcher* dispatcher_; + pw::Allocator* allocator_; + mutable pw::sync::InterruptSpinLock lock_; + pw::digital_io::DigitalInOut* monochrome_led_ PW_GUARDED_BY(lock_) = nullptr; + AsyncTimer timer_; + mutable pw::async2::CoroOrElseTask blink_task_; +}; + +} // namespace demo
diff --git a/modules/blinky/blinky.proto b/modules/blinky/blinky.proto new file mode 100644 index 0000000..3d0eced --- /dev/null +++ b/modules/blinky/blinky.proto
@@ -0,0 +1,51 @@ +// Copyright 2024 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +syntax = "proto3"; + +package blinky; + +import "pw_protobuf_protos/common.proto"; + +service Blinky { + // Toggles the LED on or off. + // If a previous `Blink` request is still running, stops it before toggling. + rpc ToggleLed(pw.protobuf.Empty) returns (pw.protobuf.Empty); + + // Sets the LED on or off. + rpc SetLed(SetLedRequest) returns (pw.protobuf.Empty); + + // Continuously blinks the board LED a specified number of times. + rpc Blink(BlinkRequest) returns (pw.protobuf.Empty); + + // Returns true or false if LED blinking is idle. + rpc IsIdle(pw.protobuf.Empty) returns (BlinkIdleResponse); +} + +message SetLedRequest { + bool on = 1; +} + +message BlinkIdleResponse { + bool is_idle = 1; +} + +message BlinkRequest { + // The interval at which to blink or pulse the LED, in milliseconds. + uint32 interval_ms = 1; + + // The number of times to blink the LED. + // If unset, blinks forever. + // If 0, stops blinking. + optional uint32 blink_count = 2; +}
diff --git a/modules/blinky/blinky_test.cc b/modules/blinky/blinky_test.cc new file mode 100644 index 0000000..66038bf --- /dev/null +++ b/modules/blinky/blinky_test.cc
@@ -0,0 +1,168 @@ +// Copyright 2024 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#include "modules/blinky/blinky.h" + +#include "pw_allocator/testing.h" +#include "pw_async2/dispatcher.h" +#include "pw_digital_io/digital_io_mock.h" +#include "pw_thread/sleep.h" +#include "pw_unit_test/framework.h" + +namespace demo { + +using AllocatorForTest = ::pw::allocator::test::AllocatorForTest<256>; +using ::pw::async2::Dispatcher; + +// Test fixtures. + +class BlinkyTest : public ::testing::Test { + protected: + using Event = ::pw::digital_io::DigitalInOutMockImpl::Event; + using State = ::pw::digital_io::State; + + static constexpr uint32_t kIntervalMs = 10; + static constexpr pw::chrono::SystemClock::duration kInterval = + pw::chrono::SystemClock::for_at_least( + std::chrono::milliseconds(kIntervalMs)); + + // TODO(b/352327457): Ideally this would use simulated time, but no + // simulated system timer exists yet. For now, relax the constraint by + // checking that the LED was in the right state for _at least_ the expected + // number of intervals. On some platforms, the fake LED is implemented using + // threads, and may sleep a bit longer. + BlinkyTest() : clock_(pw::chrono::VirtualSystemClock::RealClock()) {} + + pw::InlineDeque<Event>::iterator FirstActive() { + pw::InlineDeque<Event>& events = monochrome_led_.events(); + pw::InlineDeque<Event>::iterator event = events.begin(); + while (event != events.end()) { + if (event->state == State::kActive) { + break; + } + ++event; + } + return event; + } + + uint32_t ToMs(pw::chrono::SystemClock::duration interval) { + return std::chrono::duration_cast<std::chrono::milliseconds>(interval) + .count(); + } + + static constexpr const size_t kEventCapacity = 256; + + AllocatorForTest allocator_; + Dispatcher dispatcher_; + pw::chrono::VirtualSystemClock& clock_; + pw::digital_io::DigitalInOutMock<kEventCapacity> monochrome_led_; +}; + +// Unit tests. + +TEST_F(BlinkyTest, Toggle) { + Blinky blinky; + blinky.Init(dispatcher_, allocator_, monochrome_led_); + + auto start = clock_.now(); + blinky.Toggle(); + pw::this_thread::sleep_for(kInterval * 1); + blinky.Toggle(); + pw::this_thread::sleep_for(kInterval * 2); + blinky.Toggle(); + pw::this_thread::sleep_for(kInterval * 3); + blinky.Toggle(); + + auto event = FirstActive(); + ASSERT_NE(event, monochrome_led_.events().end()); + EXPECT_EQ(event->state, State::kActive); + EXPECT_GE(ToMs(event->timestamp - start), kIntervalMs * 0); + start = event->timestamp; + + ASSERT_NE(++event, monochrome_led_.events().end()); + EXPECT_EQ(event->state, State::kInactive); + EXPECT_GE(ToMs(event->timestamp - start), kIntervalMs * 1); + start = event->timestamp; + + ASSERT_NE(++event, monochrome_led_.events().end()); + EXPECT_EQ(event->state, State::kActive); + EXPECT_GE(ToMs(event->timestamp - start), kIntervalMs * 2); + start = event->timestamp; + + ASSERT_NE(++event, monochrome_led_.events().end()); + EXPECT_EQ(event->state, State::kInactive); + EXPECT_GE(ToMs(event->timestamp - start), kIntervalMs * 3); +} + +TEST_F(BlinkyTest, Blink) { + Blinky blinky; + blinky.Init(dispatcher_, allocator_, monochrome_led_); + + auto start = clock_.now(); + EXPECT_EQ(blinky.Blink(1, kIntervalMs), pw::OkStatus()); + while (!blinky.IsIdle()) { + dispatcher_.RunUntilStalled().IgnorePoll(); + pw::this_thread::sleep_for(kInterval); + } + + auto event = FirstActive(); + ASSERT_NE(event, monochrome_led_.events().end()); + EXPECT_EQ(event->state, State::kActive); + EXPECT_GE(ToMs(event->timestamp - start), kIntervalMs); + start = event->timestamp; + + ASSERT_NE(++event, monochrome_led_.events().end()); + EXPECT_EQ(event->state, State::kInactive); + EXPECT_GE(ToMs(event->timestamp - start), kIntervalMs); +} + +TEST_F(BlinkyTest, BlinkMany) { + Blinky blinky; + blinky.Init(dispatcher_, allocator_, monochrome_led_); + + auto start = clock_.now(); + EXPECT_EQ(blinky.Blink(100, kIntervalMs), pw::OkStatus()); + while (!blinky.IsIdle()) { + dispatcher_.RunUntilStalled().IgnorePoll(); + pw::this_thread::sleep_for(kInterval); + } + + // Every "on" and "off" is recorded. + EXPECT_GE(monochrome_led_.events().size(), 200); + EXPECT_GE(ToMs(clock_.now() - start), kIntervalMs * 200); +} + +TEST_F(BlinkyTest, BlinkSlow) { + Blinky blinky; + blinky.Init(dispatcher_, allocator_, monochrome_led_); + + auto start = clock_.now(); + EXPECT_EQ(blinky.Blink(1, kIntervalMs * 32), pw::OkStatus()); + while (!blinky.IsIdle()) { + dispatcher_.RunUntilStalled().IgnorePoll(); + pw::this_thread::sleep_for(kInterval); + } + + auto event = FirstActive(); + ASSERT_NE(event, monochrome_led_.events().end()); + EXPECT_EQ(event->state, State::kActive); + EXPECT_GE(ToMs(event->timestamp - start), kIntervalMs * 32); + start = event->timestamp; + + ASSERT_NE(++event, monochrome_led_.events().end()); + EXPECT_EQ(event->state, State::kInactive); + EXPECT_GE(ToMs(event->timestamp - start), kIntervalMs * 32); +} + +} // namespace demo
diff --git a/modules/blinky/service.cc b/modules/blinky/service.cc new file mode 100644 index 0000000..f795ca0 --- /dev/null +++ b/modules/blinky/service.cc
@@ -0,0 +1,56 @@ +// Copyright 2024 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +#define PW_LOG_MODULE_NAME "BLINKY" + +#include "modules/blinky/service.h" + +#include "pw_assert/check.h" + +namespace demo { + +void BlinkyService::Init(pw::async2::Dispatcher& dispatcher, + pw::Allocator& allocator, + pw::digital_io::DigitalInOut& monochrome_led) { + blinky_.Init(dispatcher, allocator, monochrome_led); + // Start binking once every 1000ms. + PW_CHECK_OK(blinky_.Blink(/*blink_count=*/0, /*interval_ms=*/1000)); +} + +pw::Status BlinkyService::ToggleLed(const pw_protobuf_Empty&, + pw_protobuf_Empty&) { + blinky_.Toggle(); + return pw::OkStatus(); +} + +pw::Status BlinkyService::SetLed(const blinky_SetLedRequest& request, + pw_protobuf_Empty&) { + blinky_.SetLed(request.on); + return pw::OkStatus(); +} + +pw::Status BlinkyService::IsIdle(const pw_protobuf_Empty&, + blinky_BlinkIdleResponse& response) { + response.is_idle = blinky_.IsIdle(); + return pw::OkStatus(); +} + +pw::Status BlinkyService::Blink(const blinky_BlinkRequest& request, + pw_protobuf_Empty&) { + uint32_t interval_ms = request.interval_ms == 0 ? Blinky::kDefaultIntervalMs + : request.interval_ms; + uint32_t blink_count = request.has_blink_count ? request.blink_count : 0; + return blinky_.Blink(blink_count, interval_ms); +} + +} // namespace demo
diff --git a/modules/blinky/service.h b/modules/blinky/service.h new file mode 100644 index 0000000..c1d2266 --- /dev/null +++ b/modules/blinky/service.h
@@ -0,0 +1,43 @@ +// Copyright 2024 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +#pragma once + +#include "modules/blinky/blinky.h" +#include "modules/blinky/blinky_pb/blinky.rpc.pb.h" +#include "pw_allocator/allocator.h" +#include "pw_async2/dispatcher.h" + +namespace demo { + +class BlinkyService final + : public ::blinky::pw_rpc::nanopb::Blinky::Service<BlinkyService> { + public: + void Init(pw::async2::Dispatcher& dispatcher, + pw::Allocator& allocator, + pw::digital_io::DigitalInOut& monochrome_led); + + pw::Status ToggleLed(const pw_protobuf_Empty&, pw_protobuf_Empty&); + + pw::Status SetLed(const blinky_SetLedRequest& request, pw_protobuf_Empty&); + + pw::Status Blink(const blinky_BlinkRequest& request, pw_protobuf_Empty&); + + pw::Status IsIdle(const pw_protobuf_Empty&, + blinky_BlinkIdleResponse& response); + + private: + Blinky blinky_; +}; + +} // namespace demo
diff --git a/tools/miniterm.py b/modules/timer_future/BUILD.bazel similarity index 60% rename from tools/miniterm.py rename to modules/timer_future/BUILD.bazel index 90487a6..ce6f0a4 100644 --- a/tools/miniterm.py +++ b/modules/timer_future/BUILD.bazel
@@ -1,4 +1,4 @@ -# Copyright 2023 The Pigweed Authors +# Copyright 2024 The Pigweed Authors # # Licensed under the Apache License, Version 2.0 (the "License"); you may not # use this file except in compliance with the License. You may obtain a copy of @@ -11,9 +11,16 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations under # the License. -"""Spin up a miniterm for talking to the board.""" -from serial.tools import miniterm +package(default_visibility = ["//visibility:public"]) -if __name__ == "__main__": - miniterm.main(default_baudrate=115200) +cc_library( + name = "timer_future", + srcs = ["timer_future.cc"], + hdrs = ["timer_future.h"], + deps = [ + "@pigweed//pw_async2:dispatcher", + "@pigweed//pw_chrono:system_clock", + "@pigweed//pw_chrono:system_timer", + ], +)
diff --git a/modules/timer_future/timer_future.cc b/modules/timer_future/timer_future.cc new file mode 100644 index 0000000..6d08972 --- /dev/null +++ b/modules/timer_future/timer_future.cc
@@ -0,0 +1,53 @@ +// Copyright 2024 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#include "modules/timer_future/timer_future.h" + +namespace demo { + +using ::pw::async2::Context; +using ::pw::async2::Pending; +using ::pw::async2::Poll; +using ::pw::async2::Ready; +using ::pw::async2::WaitReason; +using ::pw::chrono::SystemClock; +using ::pw::chrono::SystemTimer; + +AsyncTimer::AsyncTimer() + : waker_(), + deadline_(), + timer_([this](SystemClock::time_point) { std::move(waker_).Wake(); }) {} + +TimerFuture AsyncTimer::WaitUntil(SystemClock::time_point deadline) { + timer_.Cancel(); + waker_.Clear(); + deadline_ = deadline; + timer_.InvokeAt(deadline); + return TimerFuture(*this); +} + +TimerFuture AsyncTimer::WaitFor(SystemClock::duration duration) { + return WaitUntil(SystemClock::now() + duration); +} + +Poll<> TimerFuture::Pend(Context& cx) { + async_timer_.waker_ = cx.GetWaker(WaitReason::Unspecified()); + if (SystemClock::now() < async_timer_.deadline_) { + return Pending(); + } + async_timer_.waker_.Clear(); + return Ready(); +} + +} // namespace demo \ No newline at end of file
diff --git a/modules/timer_future/timer_future.h b/modules/timer_future/timer_future.h new file mode 100644 index 0000000..d622455 --- /dev/null +++ b/modules/timer_future/timer_future.h
@@ -0,0 +1,57 @@ +// Copyright 2024 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +#pragma once + +#include "pw_async2/dispatcher.h" +#include "pw_chrono/system_clock.h" +#include "pw_chrono/system_timer.h" + +namespace demo { + +class TimerFuture; + +class AsyncTimer { + public: + // AsyncTimer is not movable due to the timer keeping a reference to the + // waker. + AsyncTimer(); + AsyncTimer(const AsyncTimer&) = delete; + AsyncTimer& operator=(const AsyncTimer&) = delete; + AsyncTimer(AsyncTimer&&) = delete; + AsyncTimer& operator=(AsyncTimer&&) = delete; + ~AsyncTimer() { timer_.Cancel(); } + + TimerFuture WaitUntil(pw::chrono::SystemClock::time_point deadline); + TimerFuture WaitFor(pw::chrono::SystemClock::duration duration); + + private: + friend class TimerFuture; + + pw::async2::Waker waker_; + pw::chrono::SystemClock::time_point deadline_; + pw::chrono::SystemTimer timer_; +}; + +class TimerFuture { + public: + pw::async2::Poll<> Pend(pw::async2::Context& cx); + + private: + friend class AsyncTimer; + + TimerFuture(AsyncTimer& async_timer) : async_timer_(async_timer) {} + AsyncTimer& async_timer_; +}; + +} // namespace demo \ No newline at end of file
diff --git a/pigweed.json b/pigweed.json index ea9b21d..1778b2a 100644 --- a/pigweed.json +++ b/pigweed.json
@@ -5,8 +5,35 @@ "upload_local_results": true, "programs": { "default": [ - ["build", "--config=presubmit"], - ["test", "//..."] + [ + "build", + "--config=presubmit" + ], + [ + "build", + "--config=rp2040", + "//..." + ], + [ + "test", + "//..." + ], + [ + "test", + "--config=asan", + "//..." + ], + [ + "test", + "--config=tsan", + "//...", + "--runs_per_test=10" + ], + [ + "test", + "--config=ubsan", + "//..." + ] ] } }
diff --git a/requirements.in b/requirements.in deleted file mode 100644 index 120041f..0000000 --- a/requirements.in +++ /dev/null
@@ -1 +0,0 @@ -pyserial ~= 3.5
diff --git a/requirements_lock.txt b/requirements_lock.txt deleted file mode 100644 index a7b06a3..0000000 --- a/requirements_lock.txt +++ /dev/null
@@ -1,10 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.11 -# by the following command: -# -# bazel run //:pip_requirements.update -# -pyserial==3.5 \ - --hash=sha256:3c77e014170dfffbd816e6ffc205e9842efb10be9f58ec16d3e8675b4925cddb \ - --hash=sha256:c4451db6ba391ca6ca299fb3ec7bae67a5c55dde170964c7a14ceefec02f2cf0 - # via -r requirements.in
diff --git a/src/BUILD.bazel b/src/BUILD.bazel deleted file mode 100644 index 8ec1218..0000000 --- a/src/BUILD.bazel +++ /dev/null
@@ -1,71 +0,0 @@ -# Copyright 2023 The Pigweed Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. -load("//:echo.bzl", "stm32_cc_binary") - -load( - "@pigweed//pw_build:pigweed.bzl", - "pw_cc_test", -) - -package(default_visibility = ["//visibility:public"]) - -cc_binary( - name = "echo", - srcs = ["echo.cc"], - malloc = select({ - "@platforms//cpu:armv7e-m": "@pigweed//pw_malloc", - "//conditions:default": "@bazel_tools//tools/cpp:malloc", - }), - deps = [ - "@pigweed//pw_assert:backend_impl", - "@pigweed//pw_assert:check_backend_impl", - "@pigweed//pw_assert:assert_backend_impl", - "@pigweed//pw_boot", - "@pigweed//pw_sys_io", - ] + select({ - "@platforms//cpu:armv7e-m": [ - "@pigweed//pw_toolchain/arm_gcc:arm_none_eabi_gcc_support", - "@pigweed//targets/stm32f429i_disc1:basic_linker_script", - "@pigweed//targets/stm32f429i_disc1:pre_init", - ], - "//conditions:default": [], - }), -) - -stm32_cc_binary( - name = "echo.elf", - binary = ":echo", -) - -cc_library( - name = "multiply", - hdrs = ["multiply.h"], - srcs = ["multiply.cc"], -) - -# Note: Must use pw_cc_test instead of cc_test to enable on-device execution. -# See http://pigweed.dev/bazel#pw_cc_test for more details. -pw_cc_test( - name = "multiply_test", - srcs = ["multiply_test.cc"], - deps = [ - ":multiply", - ] -) - -stm32_cc_binary( - name = "multiply_test.elf", - binary = ":multiply_test", - testonly = True, -)
diff --git a/src/echo.cc b/src/echo.cc deleted file mode 100644 index a99fa4f..0000000 --- a/src/echo.cc +++ /dev/null
@@ -1,27 +0,0 @@ -// Copyright 2023 The Pigweed Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); you may not -// use this file except in compliance with the License. You may obtain a copy of -// the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations under -// the License. - -#include <cstddef> - -#include "pw_sys_io/sys_io.h" - - -int main() { - while (true) { - std::byte data; - pw::sys_io::ReadByte(&data).IgnoreError(); - pw::sys_io::WriteByte(data).IgnoreError(); - } - return 0; -}
diff --git a/src/multiply.h b/src/multiply.h deleted file mode 100644 index 3a7115a..0000000 --- a/src/multiply.h +++ /dev/null
@@ -1,16 +0,0 @@ -// Copyright 2024 The Pigweed Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); you may not -// use this file except in compliance with the License. You may obtain a copy of -// the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations under -// the License. - -// Demonstration function; multiplies a and b, returns result. -int Multiply(int a, int b);
diff --git a/src/multiply_test.cc b/src/multiply_test.cc deleted file mode 100644 index 81a548b..0000000 --- a/src/multiply_test.cc +++ /dev/null
@@ -1,26 +0,0 @@ -// Copyright 2024 The Pigweed Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); you may not -// use this file except in compliance with the License. You may obtain a copy of -// the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations under -// the License. - -// Note: Bazel/monorepo style include path, not Pigweed style. -#include "src/multiply.h" - -#include "pw_unit_test/framework.h" - -namespace { - -TEST(Multiply, TwoTimesThreeIsSix) { - ASSERT_EQ(Multiply(2, 3), 6); -} - -} // namespace
diff --git a/system/BUILD.bazel b/system/BUILD.bazel new file mode 100644 index 0000000..d005a35 --- /dev/null +++ b/system/BUILD.bazel
@@ -0,0 +1,49 @@ +# Copyright 2024 The Pigweed Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +load("@pigweed//pw_build:compatibility.bzl", "host_backend_alias") + +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "module_config", + defines = [ + # TODO: https://pwbug.dev/352389854 - Move this to per-platform config + # when platform flags are implemented. + # + # Allow us to capture two 64bit pointers in a pw::function. + "PW_FUNCTION_INLINE_CALLABLE_SIZE=16UL", + "PW_ASSERT_BASIC_ACTION=PW_ASSERT_BASIC_ACTION_EXIT", + ], +) + +label_flag( + name = "system", + build_setting_default = ":unspecified_backend", +) + +host_backend_alias( + name = "unspecified_backend", + backend = "//targets/host:system", +) + +cc_library( + name = "headers", + hdrs = [ + "system.h", + ], + deps = [ + "@pigweed//pw_digital_io", + ], +)
diff --git a/system/system.h b/system/system.h new file mode 100644 index 0000000..7d91287 --- /dev/null +++ b/system/system.h
@@ -0,0 +1,31 @@ +// Copyright 2024 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +#pragma once + +#include "pw_digital_io/digital_io.h" + +// The functions in this file return specific implementations of singleton types +// provided by the system. + +namespace demo::system { + +/// Initializes the system. This must be called before anything else in `main`. +void Init(); + +/// Starts the main system scheduler. This function never returns. +[[noreturn]] void Start(); + +pw::digital_io::DigitalInOut& MonochromeLed(); + +} // namespace demo::system
diff --git a/targets/BUILD.bazel b/targets/BUILD.bazel index 5a5ce5b..e83b707 100644 --- a/targets/BUILD.bazel +++ b/targets/BUILD.bazel
@@ -1,4 +1,4 @@ -# Copyright 2023 The Pigweed Authors +# Copyright 2024 The Pigweed Authors # # Licensed under the Apache License, Version 2.0 (the "License"); you may not # use this file except in compliance with the License. You may obtain a copy of @@ -12,15 +12,14 @@ # License for the specific language governing permissions and limitations under # the License. -platform( - name = "stm32", - constraint_values = [ - "@pigweed//pw_malloc_freelist:backend", - "@platforms//cpu:armv7e-m", - "@platforms//os:none", - "@pigweed//pw_sys_io_baremetal_stm32f429:compatible", - # Target the cortex-m4. Bazel selects the right toolchain based on - # this. - "@pw_toolchain//constraints/arm_mcpu:cortex-m4+nofp", - ], +package(default_visibility = ["//visibility:public"]) + +# TODO: https://github.com/bazelbuild/bazel/issues/22457 - Move this into the +# platform once it no longer propagates to the exec configuration. +alias( + name = "malloc", + actual = select({ + "@pico-sdk//bazel/constraint:rp2040": "@pico-sdk//src/rp2_common/pico_malloc", + "//conditions:default": "@bazel_tools//tools/cpp:malloc", + }), )
diff --git a/targets/host/BUILD.bazel b/targets/host/BUILD.bazel new file mode 100644 index 0000000..e0910b6 --- /dev/null +++ b/targets/host/BUILD.bazel
@@ -0,0 +1,36 @@ +# Copyright 2024 The Pigweed Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +load("@pigweed//pw_build:compatibility.bzl", "incompatible_with_mcu") + +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "system", + srcs = [ + "led.cc", + "system.cc", + ], + implementation_deps = [ + "@pigweed//pw_channel", + "@pigweed//pw_channel:stream_channel", + "@pigweed//pw_digital_io", + "@pigweed//pw_digital_io:digital_io_mock", + "@pigweed//pw_multibuf:simple_allocator", + "@pigweed//pw_system:async", + "@pigweed//pw_system:io", + ], + target_compatible_with = incompatible_with_mcu(), + deps = ["//system:headers"], +)
diff --git a/src/multiply.cc b/targets/host/led.cc similarity index 65% rename from src/multiply.cc rename to targets/host/led.cc index b1f6871..c8f4773 100644 --- a/src/multiply.cc +++ b/targets/host/led.cc
@@ -12,6 +12,15 @@ // License for the specific language governing permissions and limitations under // the License. -int Multiply(int a, int b) { - return a * b; +#include "pw_digital_io/digital_io_mock.h" +#include "system/system.h" + +namespace demo::system { + +pw::digital_io::DigitalInOut& MonochromeLed() { + static constexpr size_t kCapacity = 256; + static pw::digital_io::DigitalInOutMock<kCapacity> digital_io_mock; + return digital_io_mock; } + +} // namespace demo::system
diff --git a/targets/host/system.cc b/targets/host/system.cc new file mode 100644 index 0000000..8a221af --- /dev/null +++ b/targets/host/system.cc
@@ -0,0 +1,99 @@ +// Copyright 2024 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#include "system/system.h" + +#include <signal.h> +#include <stdio.h> + +#include "pw_assert/check.h" +#include "pw_channel/stream_channel.h" +#include "pw_digital_io/digital_io.h" +#include "pw_multibuf/simple_allocator.h" +#include "pw_system/io.h" +#include "pw_system/system.h" +#include "pw_thread_stl/options.h" + +using ::pw::channel::StreamChannel; +using ::pw::digital_io::DigitalIn; +using ::pw::digital_io::State; + +extern "C" { + +void CtrlCSignalHandler(int /* ignored */) { + printf("\nCtrl-C received; simulator exiting immediately...\n"); + // Skipping the C++ destructors since we want to exit immediately. + _exit(0); +} + +} // extern "C" + +void InstallCtrlCSignalHandler() { + // Catch Ctrl-C to force a 0 exit code (success) to avoid signaling an error + // for intentional exits. For example, VSCode shows an alarming dialog on + // non-zero exit, which is confusing for users intentionally quitting. + signal(SIGINT, CtrlCSignalHandler); +} + +namespace { +class VirtualInput : public DigitalIn { + public: + VirtualInput(State state) : state_(state) {} + + private: + pw::Status DoEnable(bool) override { return pw::OkStatus(); } + pw::Result<State> DoGetState() override { return state_; } + + State state_; +}; + +VirtualInput io_sw_a(State::kInactive); +VirtualInput io_sw_b(State::kInactive); +VirtualInput io_sw_x(State::kInactive); +VirtualInput io_sw_y(State::kInactive); + +} // namespace + +namespace demo::system { + +void Init() {} + +void Start() { + InstallCtrlCSignalHandler(); + printf("==========================================\n"); + printf("=== Pigweed Quickstart: Host Simulator ===\n"); + printf("==========================================\n"); + printf("Simulator is now running. To connect with a console,\n"); + printf("either run one in a new terminal:\n"); + printf("\n"); + printf(" $ bazelisk run //blinky:simulator_console\n"); + printf("\n"); + printf("one from VSCode under the 'Bazel Build Targets' explorer tab.\n"); + printf("\n"); + printf("Press Ctrl-C to exit\n"); + + static std::byte channel_buffer[16384]; + static pw::multibuf::SimpleAllocator multibuf_alloc(channel_buffer, + pw::System().allocator()); + static pw::NoDestructor<StreamChannel> channel(multibuf_alloc, + pw::system::GetReader(), + pw::thread::stl::Options(), + pw::system::GetWriter(), + pw::thread::stl::Options()); + + pw::SystemStart(*channel); + PW_UNREACHABLE; +} + +} // namespace demo::system
diff --git a/targets/rp2/BUILD.bazel b/targets/rp2/BUILD.bazel new file mode 100644 index 0000000..3cc2ea9 --- /dev/null +++ b/targets/rp2/BUILD.bazel
@@ -0,0 +1,134 @@ +# Copyright 2024 The Pigweed Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +package(default_visibility = ["//visibility:public"]) + +# This is an incomplete platform, do NOT try to pass this +# as a --platforms flag value. Use :rp2040 or :rp2350. +platform( + name = "rp2_common", + constraint_values = [ + "@freertos//:disable_task_statics", + "@pigweed//pw_build/constraints/rtos:freertos", + "@pigweed//pw_build/constraints/chipset:rp2040", # TODO: https://pwbug.dev/343487589 - Use Pico SDK constraints. + "@pigweed//pw_cpu_exception:enabled", + "@pigweed//pw_interrupt_cortex_m:backend", + "@platforms//os:none", + ], +) + +platform( + name = "rp2040", + constraint_values = [ + "@freertos//:port_ARM_CM0", + "@pico-sdk//bazel/constraint:rp2040", + # For toolchain selection. + "@platforms//cpu:armv6-m", + "@pw_toolchain//constraints/arm_mcpu:cortex-m0", + ], + parents = [":rp2_common"], +) + +platform( + name = "rp2350", + constraint_values = [ + "@freertos//:port_ARM_CM33_NTZ", + "@pico-sdk//bazel/constraint:rp2350", + # For toolchain selection. + "@platforms//cpu:armv8-m", + "@pw_toolchain//constraints/arm_mcpu:cortex-m33", + ], + parents = [":rp2_common"], +) + +cc_library( + name = "extra_platform_libs", + deps = [ + "@pico-sdk//src/rp2_common/pico_stdlib:pico_stdlib", + "@pigweed//pw_tokenizer:linker_script", + ] + select({ + "@rules_cc//cc/compiler:clang": [ + "@pigweed//pw_libcxx", + ], + "//conditions:default": [], + }), + alwayslink = 1, +) + +cc_library( + name = "freertos_config", + hdrs = [ + "config/FreeRTOSConfig.h", + ], + includes = ["config"], + deps = ["@pigweed//third_party/freertos:config_assert"], +) + +cc_library( + name = "thread_config_overrides", + defines = [ + "PW_THREAD_FREERTOS_CONFIG_JOINING_ENABLED=1", + ], +) + +cc_library( + name = "system", + srcs = [ + "led.cc", + "system.cc", + ], + implementation_deps = [ + "//system:headers", + "@pico-sdk//src/rp2_common/cmsis:cmsis_core", + "@pico-sdk//src/rp2_common/hardware_adc", + "@pico-sdk//src/rp2_common/hardware_exception:hardware_exception", + "@pico-sdk//src/rp2_common/pico_stdlib:pico_stdlib", + "@pigweed//pw_channel", + "@pigweed//pw_channel:rp2_stdio_channel", + "@pigweed//pw_cpu_exception:entry_backend_impl", + "@pigweed//pw_digital_io_rp2040", + "@pigweed//pw_multibuf:simple_allocator", + "@pigweed//pw_system:async", + "@pigweed//third_party/freertos:support", + ], + deps = ["//system:headers"], + alwayslink = 1, +) + +cc_library( + name = "unit_test_rpc_main", + testonly = True, + srcs = ["unit_test_rpc_main.cc"], + deps = [ + "//system", + "@pigweed//pw_log", + "@pigweed//pw_system:async", + "@pigweed//pw_unit_test:rpc_service", + + # These should be provided by pw_system:async. + "@pigweed//pw_assert:assert_backend_impl", + "@pigweed//pw_assert:check_backend_impl", + "@pigweed//pw_log:backend_impl", + "@pigweed//pw_system:extra_platform_libs", + ], +) + +# Several tests store `TestWorker` thread contexts in their unit test object. +# Since these thread stacks are currently 32k, the test objects may be large. +cc_library( + name = "64k_unit_tests", + defines = [ + "PW_UNIT_TEST_CONFIG_MEMORY_POOL_SIZE=65536", + ], +)
diff --git a/targets/rp2/binary.bzl b/targets/rp2/binary.bzl new file mode 100644 index 0000000..46c146f --- /dev/null +++ b/targets/rp2/binary.bzl
@@ -0,0 +1,103 @@ +# Copyright 2024 The Pigweed Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +"""Project-specific bazel transitions for rp2xxx-series chips. + +TODO: b/301334234 - Use platform-based flags and retire these transitions. +""" + +load("@pigweed//pw_build:merge_flags.bzl", "merge_flags_for_transition_impl", "merge_flags_for_transition_outputs") +load("@pigweed//targets/rp2040:transition.bzl", "RP2_SYSTEM_FLAGS") + +_COMMON_FLAGS = merge_flags_for_transition_impl( + base = RP2_SYSTEM_FLAGS, + override = { + "//system:system": "//targets/rp2:system", + "@freertos//:freertos_config": "//targets/rp2:freertos_config", + "@pico-sdk//bazel/config:PICO_CLIB": "llvm_libc", + "@pico-sdk//bazel/config:PICO_TOOLCHAIN": "clang", + "@pigweed//pw_build:default_module_config": "//system:module_config", + "@pigweed//pw_system:extra_platform_libs": "//targets/rp2:extra_platform_libs", + "@pigweed//pw_system:io_backend": "@pigweed//pw_system:sys_io_target_io", + "@pigweed//pw_toolchain:cortex-m_toolchain_kind": "clang", + "@pigweed//pw_unit_test:config_override": "//targets/rp2:64k_unit_tests", + }, +) + +_RP2040_FLAGS = { + "//command_line_option:platforms": "//targets/rp2:rp2040", +} + +_RP2350_FLAGS = { + "//command_line_option:platforms": "//targets/rp2:rp2350", +} + +def _rp2_transition(device_specific_flags): + def _rp2_transition_impl(settings, attr): + # buildifier: disable=unused-variable + _ignore = settings, attr + return merge_flags_for_transition_impl( + base = _COMMON_FLAGS, + override = device_specific_flags, + ) + + return transition( + implementation = _rp2_transition_impl, + inputs = [], + outputs = merge_flags_for_transition_outputs( + base = _COMMON_FLAGS, + override = device_specific_flags, + ), + ) + +def _rp2_binary_impl(ctx): + out = ctx.actions.declare_file(ctx.label.name) + ctx.actions.symlink(output = out, is_executable = True, target_file = ctx.executable.binary) + return [DefaultInfo(files = depset([out]), executable = out)] + +rp2040_binary = rule( + _rp2_binary_impl, + attrs = { + "binary": attr.label( + doc = "cc_binary to build for the rp2040", + cfg = _rp2_transition(_RP2040_FLAGS), + executable = True, + mandatory = True, + ), + "_allowlist_function_transition": attr.label( + default = "@bazel_tools//tools/allowlists/function_transition_allowlist", + ), + }, + doc = "Builds the specified binary for the rp2040 platform", + # This target is for rp2040 and can't be run on host. + executable = False, +) + +rp2350_binary = rule( + _rp2_binary_impl, + attrs = { + "binary": attr.label( + doc = "cc_binary to build for the rp2040", + cfg = _rp2_transition(_RP2350_FLAGS), + executable = True, + mandatory = True, + ), + "_allowlist_function_transition": attr.label( + default = "@bazel_tools//tools/allowlists/function_transition_allowlist", + ), + }, + doc = "Builds the specified binary for the rp2350 platform", + # This target is for rp2350 and can't be run on host. + executable = False, +)
diff --git a/targets/rp2/config/FreeRTOSConfig.h b/targets/rp2/config/FreeRTOSConfig.h new file mode 100644 index 0000000..65a5433 --- /dev/null +++ b/targets/rp2/config/FreeRTOSConfig.h
@@ -0,0 +1,113 @@ +// Copyright 2024 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. +#pragma once + +#include <stdint.h> + +// Disable formatting to make it easier to compare with other config files. +// clang-format off + +extern uint32_t SystemCoreClock; + +#define vPortSVCHandler SVC_Handler +#define xPortPendSVHandler PendSV_Handler +#define xPortSysTickHandler SysTick_Handler + +#if __ARM_FP +#define configENABLE_FPU 1 +#else +#define configENABLE_FPU 0 +#endif // __ARM_FP + +// TODO: Set up the MPU. +#define configENABLE_MPU 0 +#define configENABLE_TRUSTZONE 0 +#define configRUN_FREERTOS_SECURE_ONLY 1 + +#define configUSE_PREEMPTION 1 +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 +#define configUSE_TICKLESS_IDLE 0 +#define configCPU_CLOCK_HZ (SystemCoreClock) +#define configTICK_RATE_HZ ((TickType_t)1000) +#define configMAX_PRIORITIES 5 +#define configMINIMAL_STACK_SIZE ((uint32_t)(256)) +#define configMAX_TASK_NAME_LEN 16 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 1 +#define configUSE_TASK_NOTIFICATIONS 1 +#define configTASK_NOTIFICATION_ARRAY_ENTRIES 3 +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 0 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configQUEUE_REGISTRY_SIZE 10 +#define configUSE_QUEUE_SETS 0 +#define configUSE_TIME_SLICING 1 +#define configUSE_NEWLIB_REENTRANT 0 +#define configENABLE_BACKWARD_COMPATIBILITY 0 +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5 +#define configSTACK_DEPTH_TYPE uint32_t +#define configMESSAGE_BUFFER_LENGTH_TYPE size_t + +#define configSUPPORT_STATIC_ALLOCATION 1 +#define configSUPPORT_DYNAMIC_ALLOCATION 0 +#define configTOTAL_HEAP_SIZE ((size_t)(1 * 1024)) +#define configAPPLICATION_ALLOCATED_HEAP 1 + +#define configUSE_IDLE_HOOK 0 +#define configUSE_TICK_HOOK 0 +#define configCHECK_FOR_STACK_OVERFLOW 0 +#define configUSE_MALLOC_FAILED_HOOK 0 +#define configUSE_DAEMON_TASK_STARTUP_HOOK 0 + +#define configGENERATE_RUN_TIME_STATS 0 +#define configUSE_TRACE_FACILITY 0 +#define configUSE_STATS_FORMATTING_FUNCTIONS 0 + +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES 1 + +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY 3 +#define configTIMER_QUEUE_LENGTH 10 +#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE + +/* __NVIC_PRIO_BITS in CMSIS */ +#define configPRIO_BITS 4 + +#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ((1U << (configPRIO_BITS)) - 1) +#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 2 +#define configKERNEL_INTERRUPT_PRIORITY (configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS)) +#define configMAX_SYSCALL_INTERRUPT_PRIORITY (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS)) + +// Instead of defining configASSERT(), include a header that provides a +// definition that redirects to pw_assert. +#include "pw_third_party/freertos/config_assert.h" + +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_xResumeFromISR 1 +#define INCLUDE_vTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 0 +#define INCLUDE_xTaskGetIdleTaskHandle 0 +#define INCLUDE_eTaskGetState 0 +#define INCLUDE_xEventGroupSetBitFromISR 1 +#define INCLUDE_xTimerPendFunctionCall 0 +#define INCLUDE_xTaskAbortDelay 0 +#define INCLUDE_xTaskGetHandle 0 +#define INCLUDE_xTaskResumeFromISR 1
diff --git a/targets/rp2/led.cc b/targets/rp2/led.cc new file mode 100644 index 0000000..a22bcd5 --- /dev/null +++ b/targets/rp2/led.cc
@@ -0,0 +1,31 @@ +// Copyright 2024 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#include "pico/stdlib.h" +#include "pw_digital_io_rp2040/digital_io.h" +#include "system/system.h" + +namespace demo::system { + +static constexpr pw::digital_io::Rp2040Config kDefaultLedConfig = { + .pin = PICO_DEFAULT_LED_PIN, + .polarity = pw::digital_io::Polarity::kActiveHigh, +}; + +pw::digital_io::DigitalInOut& MonochromeLed() { + static ::pw::digital_io::Rp2040DigitalInOut led_sio(kDefaultLedConfig); + return led_sio; +} + +} // namespace demo::system
diff --git a/targets/rp2/system.cc b/targets/rp2/system.cc new file mode 100644 index 0000000..472ab2b --- /dev/null +++ b/targets/rp2/system.cc
@@ -0,0 +1,56 @@ +// Copyright 2024 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#include "system/system.h" + +#include "hardware/adc.h" +#include "hardware/exception.h" +#include "pico/stdlib.h" +#include "pw_channel/rp2_stdio_channel.h" +#include "pw_cpu_exception/entry.h" +#include "pw_digital_io_rp2040/digital_io.h" +#include "pw_multibuf/simple_allocator.h" +#include "pw_system/system.h" +#if defined(PICO_RP2040) && PICO_RP2040 +#include "system_RP2040.h" +#endif // defined(PICO_RP2040) && PICO_RP2040 +#if defined(PICO_RP2350) && PICO_RP2350 +#include "system_RP2350.h" +#endif // defined(PICO_RP2350) && PICO_RP2350 + +using pw::digital_io::Rp2040DigitalIn; + +namespace demo::system { + +void Init() { + // PICO_SDK inits. + SystemInit(); + stdio_init_all(); + setup_default_uart(); + stdio_usb_init(); + adc_init(); + + // Install the CPU exception handler. + exception_set_exclusive_handler(HARDFAULT_EXCEPTION, pw_cpu_exception_Entry); +} + +void Start() { + static std::byte channel_buffer[2048]; + static pw::multibuf::SimpleAllocator multibuf_alloc(channel_buffer, + pw::System().allocator()); + pw::SystemStart(pw::channel::Rp2StdioChannelInit(multibuf_alloc)); + PW_UNREACHABLE; +} + +} // namespace demo::system
diff --git a/targets/rp2/unit_test_rpc_main.cc b/targets/rp2/unit_test_rpc_main.cc new file mode 100644 index 0000000..ad0d057 --- /dev/null +++ b/targets/rp2/unit_test_rpc_main.cc
@@ -0,0 +1,35 @@ +// Copyright 2024 The Pigweed Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy of +// the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +#include "pw_log/log.h" +#include "pw_system/system.h" +#include "pw_unit_test/unit_test_service.h" +#include "system/system.h" + +namespace { + +pw::unit_test::UnitTestService unit_test_service; + +} // namespace + +int main() { + demo::system::Init(); + auto& rpc_server = pw::System().rpc_server(); + + rpc_server.RegisterService(unit_test_service); + + PW_LOG_INFO("Started test_runner app; waiting for RPCs..."); + demo::system::Start(); + PW_UNREACHABLE; +}
diff --git a/tools/BUILD.bazel b/tools/BUILD.bazel index 6d048f7..89cabc4 100644 --- a/tools/BUILD.bazel +++ b/tools/BUILD.bazel
@@ -11,28 +11,18 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations under # the License. + load("@rules_python//python:defs.bzl", "py_binary") package(default_visibility = ["//visibility:public"]) py_binary( - name = "flash", - srcs = ["flash.py"], - data = [ - "//src:echo.elf", - "@openocd//:bin/openocd", - "@pigweed//targets/stm32f429i_disc1/py/stm32f429i_disc1_utils:openocd_stm32f4xx.cfg", - ], + name = "console", + srcs = ["console.py"], deps = [ - "@pypi_pyserial//:pkg", - "@rules_python//python/runfiles", + "//modules/blinky:py_pb2", + "@pigweed//pw_protobuf:common_py_pb2", + "@pigweed//pw_rpc:echo_py_pb2", + "@pigweed//pw_system/py:pw_system_lib", ], ) - -py_binary( - name = "miniterm", - srcs = ["miniterm.py"], - deps = [ - "@pypi_pyserial//:pkg", - ], -)
diff --git a/tools/console.py b/tools/console.py new file mode 100644 index 0000000..2e8e895 --- /dev/null +++ b/tools/console.py
@@ -0,0 +1,100 @@ +# Copyright 2024 The Pigweed Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +"""Wraps pw_system's console to inject quickstart's RPC proto.""" + +import argparse +import sys + +import logging + +import pw_cli +from pw_system.device import Device as PwSystemDevice +from pw_system.device_connection import ( + add_device_args, + DeviceConnection, + create_device_serial_or_socket_connection, +) +import pw_system.console +from blinky_pb import blinky_pb2 + + +_LOG = logging.getLogger(__file__) + + +# Quickstart-specific device classes, new functions can be added here. +# similar to ones on the parent pw_system.device.Device class: +# https://cs.opensource.google/pigweed/pigweed/+/main:pw_system/py/pw_system/device.py?q=%22def%20run_tests(%22 +class Device(PwSystemDevice): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def toggle_led(self): + """Toggles the onboard (non-RGB) LED.""" + self.rpcs.blinky.Blinky.ToggleLed() + + def set_led(self, on: bool): + """Sets the onboard (non-RGB) LED.""" + self.rpcs.blinky.Blinky.SetLed(on=on) + + def blink(self, interval_ms=1000, blink_count=None): + """Sets the onboard (non-RGB) LED to blink on and off.""" + self.rpcs.blinky.Blinky.Blink( + interval_ms=interval_ms, blink_count=blink_count + ) + + +def get_device_connection( + setup_logging: bool = True, + log_level: int = logging.DEBUG, +) -> DeviceConnection: + if setup_logging: + pw_cli.log.install(level=log_level) + + parser = argparse.ArgumentParser( + prog='quickstart', + description=__doc__, + ) + parser = add_device_args(parser) + args, _remaning_args = parser.parse_known_args() + + compiled_protos = [blinky_pb2] + + device_context = create_device_serial_or_socket_connection( + device=args.device, + baudrate=args.baudrate, + token_databases=args.token_databases, + compiled_protos=compiled_protos, + socket_addr=args.socket_addr, + ticks_per_second=args.ticks_per_second, + serial_debug=args.serial_debug, + rpc_logging=args.rpc_logging, + hdlc_encoding=args.hdlc_encoding, + channel_id=args.channel_id, + # Device tracing is not hooked up yet for Pigweed Sense. + device_tracing=False, + device_class=Device, + ) + + return device_context + + +def main() -> int: + return pw_system.console.main( + compiled_protos=[blinky_pb2], + device_connection=get_device_connection(), + ) + + +if __name__ == '__main__': + sys.exit(main())
diff --git a/tools/flash.py b/tools/flash.py deleted file mode 100644 index 69a6a8b..0000000 --- a/tools/flash.py +++ /dev/null
@@ -1,74 +0,0 @@ -# Copyright 2023 The Pigweed Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. -"""Flash the echo binary to a connected STM32 Discovery Board. - -Usage: - bazel run //tools:flash -""" - -import subprocess - -from rules_python.python.runfiles import runfiles -from serial.tools import list_ports - -_BINARY_PATH = "__main__/src/echo.elf" -_OPENOCD_PATH = "openocd/bin/openocd" -_OPENOCD_CONFIG_PATH = "pigweed/targets/stm32f429i_disc1/py/stm32f429i_disc1_utils/openocd_stm32f4xx.cfg" - -# Vendor ID and model ID for the STM32 Discovery Board. -_ST_VENDOR_ID = 0x0483 -_DISCOVERY_MODEL_ID = 0x374B - - -def get_board_serial() -> str: - for dev in list_ports.comports(): - if dev.vid == _ST_VENDOR_ID and dev.pid == _DISCOVERY_MODEL_ID: - return dev.serial_number - - raise IOError("Failed to detect connected board") - - -def flash(board_serial): - r = runfiles.Create() - openocd = r.Rlocation(_OPENOCD_PATH) - binary = r.Rlocation(_BINARY_PATH) - openocd_cfg = r.Rlocation(_OPENOCD_CONFIG_PATH) - - print(f"binary Rlocation is: {binary}") - print(f"openocd Rlocation is: {openocd}") - print(f"openocd config Rlocation is: {openocd_cfg}") - - assert binary is not None - assert openocd_cfg is not None - - # Variables referred to by the OpenOCD config. - env = { - "PW_STLINK_SERIAL": board_serial, - "PW_GDB_PORT": "disabled", - } - - subprocess.check_call( - [ - openocd, - "-f", - f"{openocd_cfg}", - "-c", - f"program {binary} reset exit", - ], - env=env, - ) - - -if __name__ == "__main__": - flash(get_board_serial())
diff --git a/tools/tools.bzl b/tools/tools.bzl new file mode 100644 index 0000000..f8a35a4 --- /dev/null +++ b/tools/tools.bzl
@@ -0,0 +1,67 @@ +# Copyright 2024 The Pigweed Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +load("@bazel_skylib//rules:native_binary.bzl", "native_binary") + +def host_console(name, binary, extra_args = []): + """Create a host binary console run target. + + Args: + name: target name + binary: target binary the console is for + extra_args: additional arguments added to the console invocation + """ + native_binary( + name = name, + src = "//tools:console", + args = [ + # This arg lets us skip manual port selection. + "--socket", + "default", + "--config-file", + "$(rootpath //:pw_console_config)", + ] + extra_args, + data = [ + binary, + "//:pw_console_config", + ], + ) + +def device_console(name, binary, extra_args = []): + """Create a device binary console run target. + + Makes running a console for a binary easy, and ensures the associated binary is + up to date (but does not flash the device). + + Args: + name: target name + binary: target binary the console is for + extra_args: additional arguments added to the console invocation + """ + native_binary( + name = name, + src = "//tools:console", + args = [ + "-b", + "115200", + "--token-databases", + "$(rootpath " + binary + ")", + "--config-file", + "$(rootpath //:pw_console_config)", + ] + extra_args, + data = [ + binary, + "//:pw_console_config", + ], + )