aboutsummaryrefslogtreecommitdiff
path: root/seed
diff options
context:
space:
mode:
Diffstat (limited to 'seed')
-rw-r--r--seed/0000-index.rst22
-rw-r--r--seed/0001-the-seed-process.rst250
-rw-r--r--seed/0002-template.rst2
-rw-r--r--seed/0101-pigweed.json.rst2
-rw-r--r--seed/0102-module-docs.rst2
-rw-r--r--seed/0104-display-support.rst2
-rw-r--r--seed/0105-pw_tokenizer-pw_log-nested-tokens.rst4
-rw-r--r--seed/0107-communications.rst2
-rw-r--r--seed/0108-pw_emu-emulators-frontend.rst2
-rw-r--r--seed/0109-comms-buffers.rst2
-rw-r--r--seed/0110-memory-allocation-interfaces.rst2
-rw-r--r--seed/0111-build-systems.rst2
-rw-r--r--seed/0112-async-poll.rst2
-rw-r--r--seed/0113-bazel-cc-toolchain-api.rst2
-rw-r--r--seed/0114-channels.rst568
-rw-r--r--seed/0119-pw-sensor.rst284
-rw-r--r--seed/0119-pw-sensor/data-pipeline.svg1
-rw-r--r--seed/0119-pw-sensor/high-level-view.svg1
-rw-r--r--seed/0122-code-samples.rst211
-rw-r--r--seed/BUILD.gn246
-rw-r--r--seed/seed.gni139
21 files changed, 1626 insertions, 122 deletions
diff --git a/seed/0000-index.rst b/seed/0000-index.rst
index 218a70e77..175cd0622 100644
--- a/seed/0000-index.rst
+++ b/seed/0000-index.rst
@@ -5,24 +5,4 @@ SEED Index
==========
All pending, active, and resolved SEEDs are listed below.
-.. toctree::
- :maxdepth: 1
-
- 0001-the-seed-process
- 0002-template
- 0101-pigweed.json
- 0102-module-docs
- 0103: pw_protobuf: Past, present, and future<https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/133971>
- 0104-display-support
- 0105-pw_tokenizer-pw_log-nested-tokens
- 0106: Project Template <https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/155430>
- 0107-communications
- 0108-pw_emu-emulators-frontend
- 0109-comms-buffers
- 0110-memory-allocation-interfaces
- 0111-build-systems
- 0112-async-poll
- 0113-bazel-cc-toolchain-api
- 0114: Channels <http://pigweed-review.googlesource.com/c/pigweed/pigweed/+/175471>
- 0115: pw_sensor Sensors <http://pigweed-review.googlesource.com/c/pigweed/pigweed/+/176760>
- 0116: pw_net Sockets <http://pigweed-review.googlesource.com/c/pigweed/pigweed/+/177696>
+.. include:: seeds
diff --git a/seed/0001-the-seed-process.rst b/seed/0001-the-seed-process.rst
index 0ec702b1e..cd70cd92e 100644
--- a/seed/0001-the-seed-process.rst
+++ b/seed/0001-the-seed-process.rst
@@ -9,6 +9,8 @@
:status: Accepted
:proposal_date: 2022-10-31
:cl: 116577
+ :authors: The Pigweed Team
+ :facilitator: Unassigned
-------
Summary
@@ -94,8 +96,8 @@ Suppose you'd like to propose a new Pigweed RPC Over Smoke Signals protocol.
following the :ref:`docs-get-started-upstream` guide.
#. Claim a number for your SEED. This should be the next sequential number
- listed within the `SEED index`_'s ``toctree`` table. (We will use 5309 for
- our example.)
+ listed within the ``pw_seed_index`` in ``seed/BUILD.gn``. (We will use 5309
+ for our example.)
.. _SEED index: https://cs.opensource.google/pigweed/pigweed/+/main:seed/0000-index.rst
@@ -107,13 +109,30 @@ Suppose you'd like to propose a new Pigweed RPC Over Smoke Signals protocol.
touch seed/5309-pw_rpc-over-smoke-signals.rst
- Include your document in the GN build by modifying ``seed/BUILD.gn``:
+#. Commit your RST document and push it up to Gerrit, marking it as a
+ Work-In-Progress change, following the :ref:`docs-contributing` guide.
+
+ Your change will be assigned a number, which can be found in the Gerrit UI
+ and in its URL. For example, if your change is located at
+ ``http://pigweed-review.googlesource.com/c/pigweed/pigweed/+/987654``, its CL
+ number is ``987654``.
+
+#. Add a SEED entry to the GN build pointing to your CL by modifying
+ ``seed/BUILD.gn``.
.. code-block::
- # Insert your dependency to the doc group at the top of the file.
- pw_doc_group("docs") {
- group_deps = [
+ # Define a target for your SEED.
+ pw_seed("5309") {
+ changelist = 987654
+ title = "pw_rpc Over Smoke Signals"
+ status = "Draft"
+ author = "Your Name"
+ }
+
+ # Insert your dependency to the doc group at the bottom of the file.
+ pw_seed_index("seeds") {
+ seeds = [
":0001",
...
":5308",
@@ -121,36 +140,7 @@ Suppose you'd like to propose a new Pigweed RPC Over Smoke Signals protocol.
]
}
- # Define a doc group target for your SEED.
- pw_doc_group("5309") {
- sources = [ "5309-pw_rpc-over-smoke-signals.rst" ]
- }
-
-#. Push up your document to Gerrit, marking it as a Work-In-Progress change,
- following the :ref:`docs-contributing` guide.
-
-#. Update the ``toctree`` in the SEED index adding a row for your SEED. The
- entry should be labeled with the title of your SEED and link to your work
- in progress change.
-
- .. code-block:: rst
-
- .. toctree::
-
- 0001-the-seed-process
- ...
- 5308-some-other-seed
- 5309: pw_rpc Over Smoke Signals<https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/116577>
-
-#. Commit your change to the index (and nothing else) with the commit message
- ``SEED-xxxx: Claim SEED number``.
-
- .. code-block:: sh
-
- git add seed/0000-index.rst
- git commit -m "SEED-5309: Claim SEED number"
-
-#. Push a separate change to Gerrit with your SEED index modification and add
+#. Push a separate change to Gerrit with your SEED's GN build additions and add
GWSQ as a reviewer. Set ``Pigweed-Auto-Submit`` to +1.
.. image:: 0001-the-seed-process/seed-index-gerrit.png
@@ -175,28 +165,157 @@ Suppose you'd like to propose a new Pigweed RPC Over Smoke Signals protocol.
reviewed, push it up to Gerrit and switch the change from WIP to Active.
This will begin the open comments period.
+ Congrats! You are now a SEED author.
+
+#. The Pigweed team will now assign your SEED a SEED facilitator. The
+ facilitator will leave a comment on your SEED asking you to add their name
+ to the ``facilitator:`` entry in the header of your SEED.
+
+ The SEED facilitator is a member of the Pigweed team who will help move your
+ through the process. The SEED facilitator will be added as a reviewer on
+ your SEED and will be your primary point of contact on the Pigweed team.
+
+ Update the status of your SEED to ``"Open for Comments"`` and set the
+ assigned facilitator in its build target.
+
+ .. code-block::
+
+ pw_seed("5309") {
+ changelist = 987654
+ title = "pw_rpc Over Smoke Signals"
+ status = "Open for Comments"
+ author = "Your Name"
+ facilitator = "Your Facilitator"
+ }
+
#. Create a thread for your SEED in the ``#seed`` channel of Pigweed's
`Discord server <https://discord.gg/M9NSeTA>`_.
#. Engage with reviewers to iterate on your proposal through its comment period.
-#. When a tentative decision has been reached, a Pigweed team member will
- comment on your proposal with a summary of the discussion and reasoning,
- moving it into its Last Call phase (as described in the :ref:`Lifecycle
- <seed-0001-lifecycle>` section).
+#. During the comment period, the facilitator may comment that your proposal has
+ received "Approval of Intent" and request in the SEED comments for interested
+ reviewers to identify themselves.
+
+ The SEED status should be changed to ``Intent Approved``.
-#. Following the conclusion of the Last Call period, a Pigweed team member will
- sign off on the CL with a +2 vote, allowing it to be submitted. Update the
- reference in the SEED index with the link to your document and submit the CL.
+ At this point, initial implementation of the feature may begin landing in
+ Pigweed upstream. Any CLs prior to the SEED landing should CC both the
+ facilitator and other commenters who've indictated their interest in
+ reviewing.
- .. code-block:: rst
+ All code landed during this period should be marked as experimental and
+ protected by visibility limitations.
- .. toctree::
+#. When a tentative decision has been reached, the facilitator will comment on
+ your proposal with a summary of the discussion and reasoning, moving it into
+ its Last Call phase (as described in the
+ :ref:`Lifecycle <seed-0001-lifecycle>` section).
- 0001-the-seed-process
- ...
- 5308-some-other-seed
- 5309-pw_rpc-over-smoke-signals
+#. Following the conclusion of the Last Call period (one week from the start of
+ Last Call), the facilitator will sign off on the CL with a +2 vote, allowing
+ it to be submitted. Once a +2 has been given, the SEED author should update
+ the SEED index and submit the CL.
+
+ Before submitting, update your SEED's GN target to point to the local RST
+ file and to reflect its final status.
+
+ .. code-block::
+
+ pw_seed("5309") {
+ sources = [ "5309-pw_rpc-over-smoke-signals.rst" ]
+ title = "pw_rpc Over Smoke Signals"
+ status = "Accepted"
+ author = "Your Name"
+ }
+
+---------------------------------------
+The relationship between SEEDs and code
+---------------------------------------
+Some common questions raised by participants in the SEED process revolve around
+how SEED proposals relate to implemented code. This section addresses several of
+those questions.
+
+When should implementation of a SEED proposal begin?
+====================================================
+.. admonition:: TL;DR
+
+ The SEED's author can start writing code as soon as the intent of the
+ proposal is approved.
+
+Generally speaking, there are two stages of approval for the majority of SEED
+proposals. The first is approval of the *intent* of the SEED --- that is,
+stakeholders agree that it represents a problem that Pigweed should address,
+and the general outline of the solution is reasonable.
+
+Following this comes the approval of the specific details of the proposed
+solution. Depending on the nature of the SEED, this could range
+from higher-level component hierarchies and interactions down to concrete API
+design and precise implementation details.
+
+Once the intent of a SEED is approved, authors are free to begin implementing
+code for their proposal if they wish. This can serve as an additional reference
+for reviewers to aid their understanding of the proposal, and allow both the
+proposal and implementation to co-evolve throughout the review process.
+
+Code written alongside an active SEED can be reviewed and even merged into
+Pigweed, hidden behind experimental feature flags.
+
+At what point is the code related to a SEED considered usable?
+==============================================================
+.. admonition:: TL;DR
+
+ Code written for a SEED is considered experimental and unstable until the
+ SEED is fully approved.
+
+It is possible for code to be written, reviewed, and committed to Pigweed while
+its SEED is still in the review process. As these changes end up in Pigweed's
+main, it naturally raises the question of whether or not it is usable by other
+modules, or even external projects.
+
+Any code which is approved and submitted while its SEED remains active will be
+treated as experimental and hidden behind a feature flag. These flags will be
+configurable by other modules and downstream projects, allowing dependencies on
+experimental code. All experimental features are unstable and subject to
+potentially large changes at any time, so depending on them in non-experimental
+contexts is strongly discouraged.
+
+There may be rare circumstances where particularly time-sensitive code is
+required by projects with whom Pigweed works in close collaboration before a
+full SEED approval cycle can be completed. In these instances, the project may
+begin to depend on experimental code prematurely, and Pigweed will assist them
+with keeping up-to-date as it evolves. This type of usage is limited to only
+exceptional circumstances. In almost all cases, experimental code should be used
+at a project's own risk.
+
+Will approved SEEDs be updated in response to code changes?
+===========================================================
+.. admonition:: TL;DR
+
+ Approved SEEDs will not be updated as code evolves. Use module documentation
+ as a current reference.
+
+SEED documents are intended to capture decisions made at a point in time with
+their justification. They are not living documents which reflect the current
+state of the codebase. Generally speaking, SEEDs will not be updated following
+their acceptance and will likely diverge from the actual code as time passes.
+Some SEEDs may even become entirely obsolete if the team revisited the issue and
+decided to move in a different direction, becoming purely a historical record of
+design decisions.
+
+There are exceptions when a SEED may be modified after it has been approved;
+typically, these will occur shortly after the approval if its implementer finds
+that an important detail was incorrect or missing.
+
+If a SEED/s content is obsolete or outdated, it should ideally be marked as
+such by adding a notice or warning to the top of the SEED. However, these
+indications are marked on a best-effort basis, so SEEDs should not be be used as
+the primary source of documentation for a Pigweed feature.
+
+Users should instead rely on module documentation for up-to-date
+information about the state of a Pigweed module or feature. SEEDs can be used as
+an additional resource to learn *why* something was designed the way that it is,
+but is never necessary to understand functionality or usage.
--------------
SEED documents
@@ -240,19 +359,18 @@ for comments.**
- The SEED remains open for as long as necessary. Internally, Pigweed's review
committee will regularly meet to consider active SEEDs and determine when to
advance to them the next stage.
-- Open SEEDs are assigned owners in the core Pigweed team, who are primarily
- responsible for engaging with the author to move the SEED through its review
- process.
+- Open SEEDs are assigned facilitators in the core Pigweed team, who are
+ primarily responsible for engaging with the author to move the SEED through
+ its review process.
:bdg-warning:`Last Call` **A tentative decision has been reached, but
commenters may raise final objections.**
- A tentative decision on the SEED has been made. The decision is issued at the
- best judgement of the SEED's owner within the Pigweed team when they feel
- there has been sufficient discussion on the tradeoffs of the proposal to do
- so.
-- Transition is triggered manually by its owner, with a comment on the likely
- outcome of the SEED (acceptance / rejection).
+ best judgement of the SEED's facilitator when they feel there has been
+ sufficient discussion on the tradeoffs of the proposal to do so.
+- Transition is triggered manually by its facilitator, with a comment on the
+ likely outcome of the SEED (acceptance / rejection).
- On entering Last Call, the visibility of the SEED is widely boosted through
Pigweed's communication channels (Discord, mailing list, Pigweed Live, etc.)
to solicit any strong objections from stakeholders.
@@ -294,7 +412,7 @@ Rationale
---------
Document format
----------------
+===============
Three different documentation formats are considered for SEEDs:
- **ReST:** Used for Pigweed's existing documentation, making it a natural
@@ -305,7 +423,7 @@ Three different documentation formats are considered for SEEDs:
available.
Summary
-^^^^^^^
+-------
Based on the evaluated criteria, ReST documents provide the best overall SEED
experience. The primary issues with ReST exist around contributor tooling, which
may be mitigated with additional investment from the Pigweed team.
@@ -351,7 +469,7 @@ detailed explanations following.
- ❌
Integration
-^^^^^^^^^^^
+-----------
.. admonition:: Goal
SEED documents should seamlessly integrate with the rest of Pigweed's docs.
@@ -361,7 +479,7 @@ choice for SEEDs. The use of other formats requires additional scaffolding and
may not provide as seamless of an experience.
Indexability
-^^^^^^^^^^^^
+------------
.. admonition:: Goal
Design decisions in SEEDs should be readily available for Pigweed users.
@@ -375,7 +493,7 @@ The search function is provided by Pigweed's Sphinx build, so only documents
which exist as part of that (ReST / Markdown) are indexed.
Auditability
-^^^^^^^^^^^^
+------------
.. admonition:: Goal
Changes to SEED documents should be reviewed and recorded.
@@ -388,7 +506,7 @@ Conversely, Google Docs may be edited by anyone with access, making them prone
to unintentional modification.
Archive of discussions
-^^^^^^^^^^^^^^^^^^^^^^
+----------------------
.. admonition:: Goal
Discussions during the review of a SEED should be well-archived for
@@ -404,7 +522,7 @@ document changes do not exist as clearly-defined snapshots, making the history
of a SEED harder to follow.
Accessibility
-^^^^^^^^^^^^^
+-------------
.. admonition:: Goal
SEEDs should be easy for contributors to write.
@@ -418,7 +536,7 @@ its usage for SEEDs is heavily tied to Pigweed's documentation build. Authors
are required to set up and constantly re-run this build, slowing iteration.
Format and styling
-^^^^^^^^^^^^^^^^^^
+------------------
.. admonition:: Goal
SEED authors should have options for formatting various kinds of information
@@ -429,7 +547,7 @@ whereas ReST has a wide selection of directives and Google Docs functions as a
traditional WYSIWYG editor, making them far more flexible.
Sharing between Google and non-Google
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+-------------------------------------
.. admonition:: Goal
Both Google and non-Google contributors should easily be able to write and
diff --git a/seed/0002-template.rst b/seed/0002-template.rst
index 844c6e18a..36207c279 100644
--- a/seed/0002-template.rst
+++ b/seed/0002-template.rst
@@ -9,6 +9,8 @@
:status: Open for Comments
:proposal_date: 2022-11-30
:cl: 123090
+ :authors: The Pigweed Team
+ :facilitator: Unassigned
-------
Summary
diff --git a/seed/0101-pigweed.json.rst b/seed/0101-pigweed.json.rst
index 0e207a67b..4d3ea59b4 100644
--- a/seed/0101-pigweed.json.rst
+++ b/seed/0101-pigweed.json.rst
@@ -9,6 +9,8 @@
:status: Accepted
:proposal_date: 2023-02-06
:cl: 128010
+ :authors: Rob Mohr
+ :facilitator: Ted Pudlik
-------
Summary
diff --git a/seed/0102-module-docs.rst b/seed/0102-module-docs.rst
index 7cd8659e7..9baffebc0 100644
--- a/seed/0102-module-docs.rst
+++ b/seed/0102-module-docs.rst
@@ -9,6 +9,8 @@
:status: Accepted
:proposal_date: 2023-02-10
:cl: 128811, 130410
+ :authors: Chad Norvell
+ :facilitator: Kayce Basques
---------------------
Status (October 2023)
diff --git a/seed/0104-display-support.rst b/seed/0104-display-support.rst
index 948a4cfcb..5e06e76b0 100644
--- a/seed/0104-display-support.rst
+++ b/seed/0104-display-support.rst
@@ -9,6 +9,8 @@
:status: Accepted
:proposal_date: 2023-06-12
:cl: 150793
+ :authors: Chris Mumford
+ :facilitator: Anthony DiGirolamo
-------
Summary
diff --git a/seed/0105-pw_tokenizer-pw_log-nested-tokens.rst b/seed/0105-pw_tokenizer-pw_log-nested-tokens.rst
index a4f2966ab..159e045ce 100644
--- a/seed/0105-pw_tokenizer-pw_log-nested-tokens.rst
+++ b/seed/0105-pw_tokenizer-pw_log-nested-tokens.rst
@@ -10,6 +10,8 @@
:status: Accepted
:proposal_date: 2023-07-10
:cl: 154190
+ :authors: Gwyneth Chen
+ :facilitator: Wyatt Hepler
-------
Summary
@@ -352,7 +354,7 @@ single byte for most enums.
recovered unless an entire project is converted to log ``pw::Status``
as tokens.
- .. code:: cpp
+ .. code-block:: cpp
#include "pw_log/log.h"
#include "pw_log/tokenized_args.h"
diff --git a/seed/0107-communications.rst b/seed/0107-communications.rst
index 98f38e570..0b3de8283 100644
--- a/seed/0107-communications.rst
+++ b/seed/0107-communications.rst
@@ -9,6 +9,8 @@
:status: Accepted
:proposal_date: 2023-07-19
:cl: 157090
+ :authors: Wyatt Hepler
+ :facilitator: Carlos Chinchilla
-------
Summary
diff --git a/seed/0108-pw_emu-emulators-frontend.rst b/seed/0108-pw_emu-emulators-frontend.rst
index 187410c89..19312d86a 100644
--- a/seed/0108-pw_emu-emulators-frontend.rst
+++ b/seed/0108-pw_emu-emulators-frontend.rst
@@ -13,6 +13,8 @@
:status: Accepted
:proposal_date: 2023-06-24
:cl: 158190
+ :authors: Octavian Purdila
+ :facilitator: Armando Montanez
-------
Summary
diff --git a/seed/0109-comms-buffers.rst b/seed/0109-comms-buffers.rst
index fed016259..5fdf9ff55 100644
--- a/seed/0109-comms-buffers.rst
+++ b/seed/0109-comms-buffers.rst
@@ -9,6 +9,8 @@
:status: Accepted
:proposal_date: 2023-08-28
:cl: 168357
+ :authors: Taylor Cramer
+ :facilitator: Erik Gilling
-------
Summary
diff --git a/seed/0110-memory-allocation-interfaces.rst b/seed/0110-memory-allocation-interfaces.rst
index 931cf6391..68b560e11 100644
--- a/seed/0110-memory-allocation-interfaces.rst
+++ b/seed/0110-memory-allocation-interfaces.rst
@@ -9,6 +9,8 @@
:status: Accepted
:proposal_date: 2023-09-06
:cl: 168772
+ :authors: Alexei Frolov
+ :facilitator: Taylor Cramer
-------
Summary
diff --git a/seed/0111-build-systems.rst b/seed/0111-build-systems.rst
index a8ad6f68c..0fac2d647 100644
--- a/seed/0111-build-systems.rst
+++ b/seed/0111-build-systems.rst
@@ -9,6 +9,8 @@
:status: Accepted
:proposal_date: 2023-09-26
:cl: 171695
+ :authors: Ted Pudlik
+ :facilitator: Armando Montanez
-------
Summary
diff --git a/seed/0112-async-poll.rst b/seed/0112-async-poll.rst
index e205062d0..ce8af4856 100644
--- a/seed/0112-async-poll.rst
+++ b/seed/0112-async-poll.rst
@@ -9,6 +9,8 @@
:status: Accepted
:proposal_date: 2023-9-19
:cl: 168337
+ :authors: Taylor Cramer
+ :facilitator: Wyatt Hepler
-------
Summary
diff --git a/seed/0113-bazel-cc-toolchain-api.rst b/seed/0113-bazel-cc-toolchain-api.rst
index 758e32350..ca6cc1024 100644
--- a/seed/0113-bazel-cc-toolchain-api.rst
+++ b/seed/0113-bazel-cc-toolchain-api.rst
@@ -9,6 +9,8 @@
:status: Accepted
:proposal_date: 2023-09-28
:cl: 173453
+ :authors: Armando Montanez
+ :facilitator: Ted Pudlik
-------
Summary
diff --git a/seed/0114-channels.rst b/seed/0114-channels.rst
new file mode 100644
index 000000000..8f13fd929
--- /dev/null
+++ b/seed/0114-channels.rst
@@ -0,0 +1,568 @@
+.. _seed-0114:
+
+==============
+0114: Channels
+==============
+.. seed::
+ :number: 114
+ :name: Channels
+ :status: Accepted
+ :proposal_date: 2023-10-10
+ :cl: 175471
+ :authors: Wyatt Hepler
+ :facilitator: Carlos Chinchilla
+
+-------
+Summary
+-------
+This document proposes a new ``pw_channel`` module and
+:cpp:class:`pw::channel::Channel` class. The module is similar to
+pw_stream, with three key changes:
+
+- Supports byte stream or datagram semantics (:ref:`module-pw_stream` is a
+ subset of ``pw_channel``).
+- Provides an asynchronous API (:ref:`SEED-0112`).
+- Uses the :ref:`SEED-0109` buffers system, which enables zero-copy
+ and vectored I/O.
+
+``pw_channel`` will provide the data transmit and receive API for the upcoming
+socket abstraction.
+
+--------
+Proposal
+--------
+This SEED proposes the following:
+
+- Introduce a new ``pw_channel`` module.
+- Introduce a :cpp:class:`pw::channel::Channel` virtual interface.
+ Implementors of this interface may expose byte stream or datagram semantics.
+ All operations in this interface are async and use :ref:`seed-0109` buffers
+ to provide zero-copy operations.
+- Use ``pw_channel`` as the basis for the upcoming Pigweed sockets API.
+- Replace ``pw_stream`` with ``pw_channel`` to the extent possible.
+
+----------
+Motivation
+----------
+One of the fundamental operations of computing is sending data from one place to
+another. Examples include exchanging data with
+
+- an in-memory data structure,
+- a file in a filesystem,
+- a hardware peripheral,
+- another process, or
+- a device across a network.
+
+There are many interfaces for data exchange. Pigweed provides
+:ref:`module-pw_stream`, which is a simple synchronous API for transmitting and
+receiving data. ``pw_stream``'s simple model has made it prevalent in Pigweed.
+
+The Pigweed team is revamping its communications systems (see :ref:`seed-0107`).
+The new sockets API will be a critical piece of that story. The core job of a
+socket is to exchange data with another node in the network. ``pw_stream``'s
+purpose is to facilitate data exchange, but it is too limited for sockets.
+pw_stream is missing support for several features, including:
+
+- Datagrams – Data is a byte stream. Datagrams are not supported.
+- Unreliability – Sockets may not guarantee delivery of data. ``pw_stream``
+ assumes no data is lost if ``Write`` returns ``OK``.
+- Asynchronous operations – All functions block until the operation completes.
+- Zero copy operations – All reads and writes require data to be copied.
+- Vectored I/O – All reads and writes use a single contiguous buffer.
+- Backpressure – There is no mechanism for a stream to notify the producer that
+ it needs more time to process data.
+
+These features are fairly complex and may be exposed in a variety of ways in an
+API. This SEED proposes a new ``pw_stream``-like ``Channel`` data exchange API.
+``Channel`` provides a standard I/O interface with these advanced features.
+Like ``pw_stream``, this API will be used anywhere data needs to be read and/or
+written.
+
+---------
+Use cases
+---------
+pw_rpc
+======
+pw_rpc is a communications protocol that enables calling procedures on different
+nodes (i.e. RPCs), and sharing data between them. RPCs can be sent using
+pw_stream APIs, which are blocking.
+
+Sockets
+=======
+Sockets are a communications channel between two endpoints in a network.
+Sockets support exchanging data:
+
+- as datagrams or a stream or bytes, and
+- reliably or unreliably.
+
+pw_stream
+=========
+``Channel`` should support all use cases addressed by ``pw_stream``. These
+include:
+
+- :cpp:class:`pw::stream::NullStream` -- ``NullStream`` ignores all bytes
+ written to it and produces no bytes when read. This is used when no input or
+ output is needed.
+- :cpp:class:`pw::stream::CountingNullStream` -- Counts bytes written to it.
+ Used to to determine the size of an encoded object before it is encoded to its
+ final destination.
+- :cpp:class:`pw::stream::MemoryReader` / :cpp:class:`pw::stream::MemoryWriter`
+ -- Writes data to or reads data from a fixed, contiguous memory buffer.
+ Example uses include encoding a protobuf for transport.
+- :cpp:class:`pw::stream::SocketStream` -- Supports reading from and writing to
+ a TCP socket.
+- :cpp:class:`pw::blob_store::BlobStore::Reader` /
+ :cpp:class:`pw::blob_store::BlobStore::Writer` -- ``pw_blob_store`` uses a
+ stream interface for reading and writing. This is similar to a file object.
+
+Hardware interfaces
+===================
+It is often necessary to exchange data with hardware I/O blocks.
+The ``Channel`` API could be used to abstract communications with I/O
+interfaces.
+
+------------------
+Existing solutions
+------------------
+
+pw_stream
+=========
+pw_stream provides for a synchronous, reliable byte-oriented stream.
+
+See :ref:`module-pw_stream`.
+
+C++
+===
+C++ provides an I/O stream family of classes.
+
+Java
+====
+Java provides a hierarchy of channel classes with a variety of flavors. The
+`Channel interface
+<https://docs.oracle.com/javase/8/docs/api/java/nio/channels/Channel.html>`_
+provides just two methods: ``isOpen()`` and ``close()``. Various I/O operations
+are mixed in through different interfaces. ``Channel`` supports `byte stream
+<https://docs.oracle.com/javase/8/docs/api/java/nio/channels/ByteChannel.html>`_,
+`datagram
+<https://docs.oracle.com/javase/8/docs/api/java/nio/channels/DatagramChannel.html>`_,
+`asynchronous <https://docs.oracle.com/javase/8/docs/api/java/nio/channels/AsynchronousChannel.html>`_,
+and `scatter <https://docs.oracle.com/javase/8/docs/api/java/nio/channels/ScatteringByteChannel.html>`_/
+`gather <https://docs.oracle.com/javase/8/docs/api/java/nio/channels/GatheringByteChannel.html>`_ IO.
+
+C#
+==
+The C# programming language offers a stream class similar to pw_stream and the
+proposed pw_channel module. It supports synchronous and asynchronous operations
+on a stream of bytes.
+https://learn.microsoft.com/en-us/dotnet/api/system.io.stream?view=net-7.0
+
+C#’s Channel API has a different intent than pw_channel. Its purpose is to
+synchronize objects between endpoints, and is somewhat different from what is
+proposed here.
+https://learn.microsoft.com/en-us/dotnet/api/system.threading.channels?view=net-7.0
+
+------------
+Requirements
+------------
+* Support data transmission for the upcoming sockets API (:ref:`seed-0107`):
+
+ - reliable byte stream (``SOCK_STREAM``)
+ - unreliable datagram (``SOCK_DGRAM``)
+ - reliable datagram (``SOCK_SEQPACKET``)
+
+* Asynchronous operations.
+* Efficient, minimally copying buffer with ``MultiBuf`` (:ref:`seed-0109`).
+
+------
+Design
+------
+Conceptually, a channel is a sequence of bytes or datagrams exchanged between
+two endpoints. An endpoint can be anything that produces or consumes data, such
+as an in-memory data structure, a file in a filesystem, a hardware peripheral,
+or a network socket. Both endpoints may be ``Channel`` implementations, or the
+``Channel`` may simply forward to something that provides compatible semantics,
+e.g. a memory buffer or OS socket.
+
+In Unix, "everything is a file". File descriptors provide a common I/O interface
+used for everything from files to pipes to sockets to hardware devices. Channels
+fill a similar role as POSIX file descriptors.
+
+Channel semantics
+=================
+pw_channel will provide the data exchange API for Pigweed’s upcoming network
+sockets. To this end, ``Channel`` supports the following socket semantics:
+
+- reliable byte stream (``SOCK_STREAM``)
+- unreliable datagram (``SOCK_DGRAM``)
+- reliable datagram (``SOCK_SEQPACKET``)
+
+Reliability and data type (stream versus datagram) are essential aspects of
+channel semantics. These properties affect how code that uses the APIs is
+written. A channel with different semantics cannot be swapped for another
+without updating the assumptions in the surrounding code.
+
+Data type: datagrams & byte streams
+-----------------------------------
+Fundamentally, a channel involves sending data from one endpoint to another.
+The endpoints might both be ``Channel`` instances (e.g. two sockets). Or, one
+endpoint could be a ``Channel`` while the other is an in-memory data structure,
+file in a file system, or hardware peripheral.
+
+The data type dictates the basic unit of data transmission. Datagram channels
+send and receive datagrams: "self-contained, independent entit[ies] of data"
+(`RFC 1594 <https://www.rfc-editor.org/rfc/rfc1594.txt>`_). Datagrams contain a
+payload of zero or more bytes. pw_channel does not define a maximum payload size
+for datagrams.
+
+Byte stream channels send and receive an arbitrary sequence of bytes.
+Zero-length byte stream writes are no-ops and may not result in any bytes being
+transmitted.
+
+In terms of the channels API, ``Read``, ``Write``, and ``Seek`` functions have
+different meanings for byte and and datagram channels. For byte stream channels,
+these functions work with an arbitrary number of bytes. For datagram channels,
+``Read``, ``Write``, and ``Seek`` are in terms of datagrams.
+
+Reliable channels
+-----------------
+Reliable channels guarantee that their data is received in order and without
+loss. The API user does not have to do anything to ensure this. After a write is
+accepted, the user will never have to retry it. Reads always provide data in
+order without loss. The channel implementation is responsible for this.
+
+For some channels, reliability is trivial; for others it requires significant
+work:
+
+- A memory channel that writes to a buffer is trivially reliable.
+- A socket communicating across a network will require a complex protocol such
+ as TCP to guarantee that the data is delivered.
+
+Initially, only reliable byte-oriented channels will be supported. Unreliable
+byte streams are not commonly supported, and would be difficult to apply in many
+use cases. There are circumstances where unreliable byte streams do makes sense,
+such as reading time-sensitive sensor data, where the consumer only wants the
+very latest data regardless of drops. Unreliable byte streams may be added in
+the future.
+
+Data loss
+^^^^^^^^^
+Data is never silently lost in a reliable channel. Unrecoverable data loss
+always results in the eventual closure of the channel, since a fundamental
+invariant of the channel cannot be maintained.
+
+A few examples:
+
+- A write to a TCP channel fails because of a transient hardware issue. The
+ channel and underlying TCP connection are closed.
+- A TCP channel times out on a retry. The channel and underlying TCP connection
+ are closed.
+- A write to a channel that fills a ring buffer is requested. A ``MultiBuf`` for
+ the write is not provided immediately because the ring buffer is full. The
+ channel stays open, but the write is delayed until the ring buffer has
+ sufficient space.
+
+Reliability & connections
+^^^^^^^^^^^^^^^^^^^^^^^^^
+Reliable channels operate as if they have a connection, even if the underlying
+implementation does not establish a connection. This specifically means that:
+
+- It is assumed that the peer endpoint will receive data for which the write
+ call succeeded.
+- If data is lost, the error will be reported in some form and the channel will
+ be closed.
+
+For example, a TCP socket channel would maintain an explicit connection, while a
+ring buffer channel would not.
+
+Unreliable channels
+-------------------
+Unreliable datagram channels make no guarantees about whether datagrams are
+delivered and in what order they arrive. Users are responsible for tracking
+drops and ordering if required.
+
+Unreliable channels should report read and write failures whenever possible,
+but an ``OK`` write does not indicate that the data is received by the other
+endpoint.
+
+Flow control, backpressure, and ``ConservativeLimit``
+=====================================================
+A channel may provide backpressure through its async write API. The
+``PollWritable`` method should be used to ensure that the channel is ready
+to receive calls to ``Write``. Additionally, the ``MultiBufAllocator`` may wait
+to provide a ``MultiBuf`` for writing until memory becomes available.
+
+pw_stream offered a notion of flow control through the
+:cpp:func:`pw::stream::Stream::ConservativeWriteLimit` function. Code using a
+stream could check the write limit prior to writing data to determine if the
+stream is ready to receive more. This function will not be provided in
+``pw_channel``.
+
+Openness / closedness
+=====================
+pw_channel will have an explicit open/closed concept that ``pw_stream`` lacks.
+Reads and writes may succeed when the channel is open. Reads and writes never
+succeed when the channel is closed.
+
+The channel API supports closing a channel, but does not support opening a
+channel. Channels are opened by interacting with a concrete class.
+
+Reliable channels are closed if unrecoverable data loss occurs. Unreliable
+channels may be closed when reads or writes are known to fail (e.g. a
+cable was unplugged), but this is not required.
+
+Synchronous APIs
+================
+The ``pw_channel`` class may provide synchronous versions of its functions,
+implementated in terms of the asynchronous API. These will poll the asynchronous
+API until it completes, blocking on a binary semaphore or similar primitive if
+supported. This will leverage a ``pw_async`` helper for this purpose.
+
+Channel Class Capabilities
+==========================
+``Channel`` s may offer any of five capabilities:
+
+.. list-table::
+ :header-rows: 1
+
+ * - Capability
+ - Description
+ * - ``kReliable``
+ - Data is guaranteed to arrive in order, without loss.
+ * - ``kSeekable``
+ - The read/write position may be changed via the ``Seek`` method.
+ * - ``kDatagram``
+ - Data is guaranteed to be received in whole packets matching the size and
+ contents of a single ``Write`` call.
+ * - ``kReadable``
+ - Supports reading data.
+ * - ``kWritable``
+ - Supports writing data
+
+These capabilities are expressed as generic arguments to the ``Channel`` class,
+e.g. ``Channel<kReadable | kReliable>`` for a ``Channel`` that is readable and
+reliable. Aliases are provided for common combinations, such as ``ByteStream``
+for a reliable non-seekable non-datagram stream of bytes (such as a TCP stream).
+Certain nonsensical combinations, such as a channel that is ``kSeekable`` but
+not ``kReadable`` or ``kWritable`` are disallowed via ``static_assert``.
+
+Conversion
+----------
+Channels may be freely converted to channels with fewer capabilities, e.g.
+``Channel<kReadable | kWritable>`` may be used as a ``Channel<kReadable>``.
+This allows Channels with compatible semantics to be substituted for one another
+safely.
+
+Shared Base Class for Minimal Code Size
+---------------------------------------
+``Channel`` also inherits from an ``AnyChannel`` base class which provides the
+underlying ``virtual`` interface. Sharing a single base class avoids multiple
+inheritance, minimizing vtable overhead.
+
+Prototype Demonstrating Channel Capabilities
+--------------------------------------------
+A prototype demonstrating this interface can be seen `here
+<https://godbolt.org/z/3c4M3Y17r>`_.
+
+API sketch
+==========
+An outline of the ``AnyChannel`` base class follows. ``AnyChannel`` will rarely
+be used directly, since it makes no guarantees about any channel capabilities or
+the data type. The function signatures and comments apply to all derived classes,
+however.
+
+.. code-block:: cpp
+
+ namespace pw::channel {
+
+ /// A generic data channel that may support reading or writing bytes.
+ ///
+ /// Note that this channel should be used from only one ``pw::async::Task``
+ /// at a time, as the ``Poll`` methods are only required to remember the
+ /// latest ``pw::async::Context`` that was provided.
+ class AnyChannel {
+ public:
+ // Properties
+ [[nodiscard]] bool reliable() const;
+ [[nodiscard]] DataType data_type() const;
+ [[nodiscard]] bool readable() const;
+ [[nodiscard]] bool writable() const;
+ [[nodiscard]] Seekability seekable() const;
+
+ [[nodiscard]] bool is_open() const;
+
+ // Write API
+
+ // Checks whether a writeable channel is *currently* writeable.
+ //
+ // This should be called before attempting to ``Write``, and may be called
+ // before allocating a write buffer if trying to reduce memory pressure.
+ //
+ // If ``Ready`` is returned, a *single* caller may proceed to ``Write``.
+ //
+ // If ``Pending`` is returned, ``cx`` will be awoken when the channel
+ // becomes writeable again.
+ //
+ // Note: this method will always return ``Ready`` for non-writeable
+ // channels.
+ MaybeReady<> PollWritable(pw::async::Context& cx);
+
+ // Gives access to an allocator for write buffers. The MultiBufAllocator
+ // provides an asynchronous API for obtaining a buffer.
+ //
+ // This allocator must *only* be used to allocate the next argument to
+ // ``Write``. The allocator must be used at most once per call to
+ // ``Write``, and the returned ``MultiBuf`` must not be combined with
+ // any other ``MultiBuf`` s or ``Chunk`` s.
+ //
+ // Write allocation attempts will always return ``std::nullopt`` for
+ // channels that do not support writing.
+ MultiBufAllocator& GetWriteAllocator();
+
+ // Writes using a previously allocated MultiBuf. Returns a token that
+ // refers to this write. These tokens are monotonically increasing, and
+ // FlushPoll() returns the value of the latest token it has flushed.
+ //
+ // The ``MultiBuf`` argument to ``Write`` may consist of either:
+ // (1) A single ``MultiBuf`` allocated by ``GetWriteAllocator()``
+ // that has not been combined with any other ``MultiBuf`` s
+ // or ``Chunk``s OR
+ // (2) A ``MultiBuf`` containing any combination of buffers from sources
+ // other than ``GetWriteAllocator``.
+ //
+ // This requirement allows for more efficient use of memory in case (1).
+ // For example, a ring-buffer implementation of a ``Channel`` may
+ // specialize ``GetWriteAllocator`` to return the next section of the
+ // buffer available for writing.
+ //
+ // May fail with the following error codes:
+ //
+ // * OK - Data was accepted by the channel
+ // * UNIMPLEMENTED - The channel does not support writing.
+ // * UNAVAILABLE - The write failed due to a transient error (only applies
+ // to unreliable channels).
+ // * FAILED_PRECONDITION - The channel is closed.
+ Result<WriteToken> Write(MultiBuf&&);
+
+ // Flushes pending writes.
+ //
+ // Returns a ``MaybeReady`` indicating whether or not flushing has
+ // completed.
+ //
+ // After this call, ``LastFlushed`` may be used to discover which
+ // ``Write`` calls have successfully finished flushing.
+ //
+ // * Ready(OK) - All data has been successfully flushed.
+ // * Ready(UNIMPLEMENTED) - The channel does not support writing.
+ // * Ready(FAILED_PRECONDITION) - The channel is closed.
+ // * Pending - Data remains to be flushed.
+ [[nodiscard]] MaybeReady<pw::Status> PollFlush(async::Context& cx);
+
+ // Returns the latest ```WriteToken``` that was successfully flushed.
+ //
+ // Note that a ``Write`` being flushed does not necessarily mean that the
+ // data was received by the remote. For unreliable channels, flushing may
+ // simply mean that data was written out, not that it was received.
+ [[nodiscard]] WriteToken LastFlushed() const;
+
+ // Read API
+
+ // Returns a MultiBuf read data, if available. If data is not available,
+ // invokes cx.waker() when it becomes available.
+ //
+ // For datagram channels, each successful read yields one complete
+ // datagram. For byte stream channels, each successful read yields some
+ // number of bytes.
+ //
+ // Channels only support one read operation / waker at a time.
+ //
+ // * OK - Data was read into a MultiBuf.
+ // * UNIMPLEMENTED - The channel does not support reading.
+ // * FAILED_PRECONDITION - The channel is closed.
+ // * OUT_OF_RANGE - The end of the stream was reached. This may be though
+ // of as reaching the end of a file. Future reads may succeed after
+ // ``Seek`` ing backwards, but no more new data will be produced. The
+ // channel is still open; writes and seeks may succeed.
+ MaybeReady<Result<MultiBuf>> PollRead(async::Context& cx);
+
+ // On byte stream channels, reads up to max_bytes from the channel.
+ // This function is hidden on datagram-oriented channels.
+ MaybeReady<Result<MultiBuf>> PollRead(async::Context& cx, size_t max_bytes);
+
+ // Changes the position in the stream.
+ //
+ // Any ``PollRead`` or ``Write`` calls following a call to ``Seek`` will be
+ // relative to the new position. Already-written data still being flushed
+ // will be output relative to the old position.
+ //
+ // * OK - The current position was successfully changed.
+ // * UNIMPLEMENTED - The channel does not support seeking.
+ // * FAILED_PRECONDITION - The channel is closed.
+ // * NOT_FOUND - The seek was to a valid position, but the channel is no
+ // longer capable of seeking to this position (partially seekable
+ // channels only).
+ // * OUT_OF_RANGE - The seek went beyond the end of the stream.
+ Status Seek(ptrdiff_t position, Whence whence);
+
+ // Returns the current position in the stream, or kUnknownPosition if
+ // unsupported.
+ size_t Position() const;
+
+ // Closes the channel, flushing any data.
+ //
+ // * OK - The channel was closed and all data was sent successfully.
+ // * DATA_LOSS - The channel was closed, but not all previously written
+ // data was delivered.
+ // * FAILED_PRECONDITION - Channel was already closed, which can happen
+ // out-of-band due to errors.
+ MaybeReady<pw::Status> PollClose(async::Context& cx);
+
+ private:
+ virtual bool do_reliable() const;
+ virtual DataType do_data_type() const;
+ virtual bool do_readable() const;
+ virtual bool do_writable() const;
+ virtual Seekability do_seekable() const;
+ virtual bool do_is_open() const;
+
+ // Virtual interface.
+ virtual MultiBufAllocator& DoGetWriteBufferAllocator() = 0;
+
+ virtual MaybeReady<> PollWritable(async::Context& cx) = 0;
+
+ virtual Result<WriteToken> DoWrite(MultiBuf&& buffer) = 0;
+
+ virtual WriteToken DoPollFlush(async::Context& cx) = 0;
+
+ [[nodiscard]] WriteToken LastFlushed() const = 0;
+
+ // The max_bytes argument is ignored for datagram-oriented channels.
+ virtual MaybeReady<Result<MultiBuf>> DoReadPoll(
+ async::Context& cx, size_t max_bytes) = 0;
+
+ virtual DoSeek(ptrdiff_t position, Whence whence) = 0;
+
+ virtual size_t DoPosition() const { return kUnknownPosition; }
+
+ virtual async::MaybeReady<Status> DoClosePoll(async::Context& cx);
+ };
+ } // namespace pw::channel
+
+pw_channel and pw_stream
+========================
+As described, ``pw_channel`` is closely based on ``pw_stream``. It adds async,
+``MultiBuf``, and new socket-inspired semantics.
+
+``pw_channel`` is intended to supersede ``pw_stream``. There are a few options
+for how to reconcile the two modules. From most to least ideal, these are:
+
+- Fully replace ``pw_stream`` with ``pw_channel`` and remove the ``pw_stream``
+ module.
+- Rework ``pw_stream`` so it inherits from ``pw::channel::Channel``.
+- Keep ``pw_stream``, but provide adapters to convert between ``pw_stream`` and
+ ``pw_channel``.
+
+Fully replacing ``pw_stream`` with ``pw_channel`` could be complicated due to:
+
+- Potential code size increase because of ``MultiBuf`` and the async poll model.
+- The scale of migrating the all Pigweed users off of ``pw_stream``.
+- Increased API complexity imposing a burden on Pigweed users.
diff --git a/seed/0119-pw-sensor.rst b/seed/0119-pw-sensor.rst
new file mode 100644
index 000000000..64d61827e
--- /dev/null
+++ b/seed/0119-pw-sensor.rst
@@ -0,0 +1,284 @@
+.. _seed-0119:
+
+=============
+0119: Sensors
+=============
+.. seed::
+ :number: 0119
+ :name: Sensors
+ :status: Accepted
+ :proposal_date: 2023-10-18
+ :cl: 175479
+ :authors: Yuval Peress
+ :facilitator: Taylor Cramer
+
+-------
+Summary
+-------
+This SEED proposes that Pigweed provide a full end-to-end sensor solution,
+including a shared set of abstractions and communication primitives. This
+will allow Pigweed users to build reusable drivers and portable applications.
+
+----------
+Motivation
+----------
+Sensors are part of nearly every embedded device. However, sensor drivers and
+application logic are often bespoke. Current clients of Pigweed must write
+sensor drivers using various bus APIs. This results in drivers and applications
+that are deeply integrated and not reusable. When drivers are custom-built for
+particular applications, they frequently omit significant functionality needed
+by other potential users.
+
+This solution does not scale.
+
+Introducing a standard sensor driver interface will allow Pigweed users to
+build drivers that can be reused across applications, and applications that
+are compatible with multiple different drivers.
+
+A second layer of a sensor framework will then be introduced. This secondary
+layer will provide functionality required for more advanced applications and
+will include support for virtual sensors and multi-client connections per
+sensor. It will also be compatible with Android's `CHRE`_.
+
+---------
+Prior Art
+---------
+Sensor APIs are available today on many platforms:
+
+- `Android`_
+- `Apple iOS and macOS`_
+- `Linux`_
+- `Windows`_
+- `Zephyr`_
+
+Where possible, we strive to make it possible for Pigweed's Sensor API to
+delegate to these platform-level APIs without significant loss of
+functionality.
+
+However, where performance, code size, API comprehensibility, or reusability
+are of particular concern, priority is given to ensuring that Pigweed-native
+sensor drivers and APIs meet the needs of Pigweed applications.
+
+-------------
+System Design
+-------------
+At the high level, the ``pw_sensor`` module will introduce the following
+concepts:
+
+- ``Sensor``: a class which will enable a single user to **configure**,
+ **read**, or **stream** data. The implementation can vary. Some
+ implementations may call down to an already implemented sensor driver of the
+ underlying RTOS, others may be software sensors which themselves will open
+ ``Connection``\s to other sensors, or in other cases, the ``Sensor``
+ implementation will actually perform remote calls to a sensor on another SoC
+ or board.
+- ``Connection``: a class which will enable us to abstract away the single
+ client concept of the ``Sensor``. A ``Connection`` is owned by some logic
+ and uses the same configuration as the ``Sensor``. The only difference is
+ that the Pigweed provided sensor framework will then mux all the
+ configurations targeting the same sensor into a single configuration. This
+ single configuration will be used for the actual ``Sensor`` object (see
+ `pw sensor configuration mux`_ as an example). When data becomes
+ available, the sensor framework will demux the data and provide it to the
+ various clients based on the live ``Connection``\s.
+
+.. image:: 0119-pw-sensor/high-level-view.svg
+
+Actually reading the data is a 2 step process. The first is getting the data
+from the ``Sensor`` object. The second step is decoding it into something
+that's usable. Data from the first step is generally still in register format
+and includes some headers from the driver which will allow the ``Decoder`` to
+convert the values to the appropriate representation (most likely ``float``).
+
+.. image:: 0119-pw-sensor/data-pipeline.svg
+
+-----------------
+The Sensor Driver
+-----------------
+The sensor driver provides the 3 functionalities listed above (configuring,
+reading, and streaming).
+
+Each sensor may assume it has exactly 1 caller. It is up to the application to
+leverage the right locking and arbitration mechanisms if a sensor is to be
+shared between parts of the code. Doing this keeps the driver implementor's job
+much simpler and allows them to focus on performance, testing, and simplicity.
+In order to provide consumers of sensor data with more advanced features, a
+sensor framework will also be provided and discussed in the following section
+:ref:`the sensor framework`.
+
+Asynchronous APIs
+-----------------
+Bus transactions are asynchronous by nature and often can be set up to use an
+interrupt to signal completion. By making the assumption that all reading,
+writing, and configuring of the sensor are asynchronous, it's possible to
+provide an API which is callable even from an interrupt context. The final
+result of any operation of the API will use the ``pw_async`` logic. Doing so
+will allow the clients to avoid concerns about the context in which callbacks
+are called and having to schedule work on the right thread. Instead, they're
+able to rely on the async dispatcher.
+
+Configuring
+-----------
+Sensors generally provide some variable configurations. In some cases, these
+configurations are global (i.e. they apply to the device). An example of such
+global configuration might be a FIFO watermark (via a batching duration). In
+other cases, the configuration might apply to specific sub-sensors /
+measurements. An example of a specific configuration attribute can be the sample
+rate which on an Inertial Measurement Unit (IMU) might be an acceleration and
+rotational velocity. We can describe each configuration with the following:
+
+- Measurement type: such as acceleration or rotational velocity
+- Measurement index: the index of the measurement. This is almost always 0, but
+ some sensors do provide multiple samples of the same measurement type (range
+ finders). In which case it's possible that we would need to configure
+ separate instances of the sensor.
+- Attribute: such as the sample rate, scale, offset, or batch duration
+- Value: the value associated with the configuration (might be a ``bool``,
+ ``float``, ``uint64_t``, or something else entirely).
+
+Here's an example:
+
++---------------+----------------+--------+
+| Measurement | Attribute | Value |
++-------+-------+----------------+--------+
+| Type | Index | | |
++=======+=======+================+========+
+| Accel | 0 | Sample Rate | 1000Hz |
++-------+-------+----------------+--------+
+| All | 0 | Batch duration | 200ms |
++-------+-------+----------------+--------+
+
+Reading
+-------
+Reading a sensor involves initiating some I/O which will fetch an unknown amount
+of data. As such, the operation will require some ``Allocator`` to be used along
+with a possible *Measurement Type* filter to limit the amount of data being
+retrieved and stored. When complete, the result will be provided in a
+``pw::ConstByteSpan`` which was allocated from the ``Allocator``. This byte span
+can be cached or possibly sent over a wire for decoding.
+
+Streaming
+---------
+Streaming data from a sensor is effectively the same as reading the sensor with
+minor considerations. Instead of filtering "what" data we want, we're able to
+specify "when" we want the data. This happens in the form of one or more
+interrupts. There will be some additional control over the data returned from
+the stream; it will come in the form of an operation. 3 operations will be
+supported for streams:
+
+- ``Include``: which tells the driver to include any/all associated data with
+ the trigger. As an example, a batching trigger will include all the data from
+ the FIFO so it can be decoded later.
+- ``Drop``: which tells the driver to get rid of the associated data and just
+ report that the event happened. This might be done on a FIFO full event to
+ reset the state and start over.
+- ``Noop``: which tells the driver to just report the event and do nothing with
+ the associated data (maybe the developer wants to read it separately).
+
+.. note::
+ We do not allow specifying a measurement filter like we do in the reading API
+ because it would drastically increase the cost of the driver developer.
+ Imagine a trigger for the stream on an IMU using the batch duration where we
+ want to only get the acceleration values from the FIFO. This scenario doesn't
+ make much sense to support since the caller should simply turn off the
+ gyroscope in the FIFO via the configuration. Having the gyroscope
+ measurements in the FIFO usually means they will simply be discarded when
+ read. This puts a very heavy burden on the driver author to place a filter in
+ the reader logic as well as in the decoder.
+
+Decoder
+-------
+The decoder provides functionality to peek into the raw data returned from the
+``Sensor``. It should implement functionality such as:
+
+- Checking if a measurement type is present in the buffer. If so, how many
+ :ref:`pw sensor define frame` and indices?
+- Checking how much memory will be required to decode the frame header (which
+ includes information like the base timestamp, frame count, etc) and each frame
+ of data.
+- Decoding frames of data. There will be a hard mapping of a measurement type to
+ data representation. Example: a measurement type of *Acceleration* will always
+ decode to a ``struct acceleration_data``.
+
+.. _the sensor framework:
+
+--------------------
+The Sensor Framework
+--------------------
+The sensor framework is an abstraction above the ``Sensor`` class which provides
+a superset of features but on a ``Connection`` object. The framework will be a
+singleton object and will provide consumers the following:
+
+- List all sensors represented as read-only ``SensorInfo`` objects.
+- Ability to open/close connections. When a connection is open, a ``Connection``
+ object is returned. The connection can be closed by either calling
+ ``Connection::Close()`` or simply calling the ``Connection``\s deconstructor.
+
+Once the sensor framework is linked into the application, ``Sensor`` objects
+should not be manipulated directly. Instead, the only direct client of the
+``Sensor``\s is the framework. Users can request a list of all the sensors
+(``SensorInfo`` objects). Once the client finds the sensor they want to listen
+to, they can request a ``Connection`` to be opened to that sensor. A
+``Connection`` provides very similar functionality to that of the ``Sensor`` but
+is owned by the framework. As an example, a configuration change made on the
+``Connection`` will trigger the framework to mux together all the configurations
+of all the connections that point to the same ``Sensor``. Once complete, a
+single configuration will be selected and set on the ``Sensor``. Similarly, when
+the ``Sensor`` produces data, the data will be demuxed and sent to all the open
+``Connection``\s.
+
+Virtual Sensors
+---------------
+This framework provides an interesting way to build portable virtual (soft)
+sensors. If the library containing the virtual sensors depends on the framework,
+it's possible for the virtual sensors to own connections, configure the sources,
+and perform all the necessary signal processing without compromising other
+unknown clients of the same sensor (since the framework handles all the
+configuration arbitration).
+
+As an example, a hinge angle sensor could accept 2 ``Connection`` objects to
+accelerometers in its constructor. When the hinge angle sensor is configured
+(such as sample rate) it would pass the configuration down to the connections
+and request the same sample rate from the 2 accelerometers.
+
+--------
+Glossary
+--------
+
+.. _pw sensor define frame:
+
+Frame
+ A single time slice. Usually this is used to reference a single sample of
+ multiple sensor measurement types such as an IMU measuring both acceleration
+ and rotational velocity at the same time.
+
+--------
+Examples
+--------
+
+.. _pw sensor configuration mux:
+
+Pigweed will provide some default mechanism for muxing together
+``Configuration`` objects. Like many other modules and backends in Pigweed, this
+mechanism will be overridable by the application. Below is an example of what it
+might look like:
+
+- Assume a client requests samples at 1kHz
+- Assume a second client requests samples at 1.1kHz
+- The resulting sample rate is 1.1kHz, but it's much more likely that the sensor
+ doesn't support 1.1kHz and will instead be giving both clients 2kHz of
+ samples. It will then be up to both clients to decimate the data correctly.
+
+.. note::
+ Decimating 2kHz down to 1.1kHz isn't as simple as just throwing away 9
+ samples for every 20. What the client is likely to do is use a weighted
+ average in order to simulate the 1.1kHz. It's likely that Pigweed should at
+ some point provide a decimation library with a few common strategies which
+ would help developers with the task.
+
+.. _`Android`: https://developer.android.com/develop/sensors-and-location/sensors/sensors_overview
+.. _`Apple iOS and macOS`: https://developer.apple.com/documentation/sensorkit
+.. _CHRE: https://source.android.com/docs/core/interaction/contexthub
+.. _Linux: https://www.kernel.org/doc/html/v4.14/driver-api/iio/intro.html
+.. _Windows: https://learn.microsoft.com/en-us/windows/win32/sensorsapi/the-sensor-object
+.. _Zephyr: https://docs.zephyrproject.org/apidoc/latest/group__sensor__interface.html
diff --git a/seed/0119-pw-sensor/data-pipeline.svg b/seed/0119-pw-sensor/data-pipeline.svg
new file mode 100644
index 000000000..5a9ea56bb
--- /dev/null
+++ b/seed/0119-pw-sensor/data-pipeline.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:lucid="lucid" width="1242.67" height="681"><g transform="translate(-399.4999999999999 -446.83333333333337)" lucid:page-tab-id="Jy1QJpHCM_dY"><path d="M0 0h2000v1500H0z" fill="#fff"/><path d="M961.67 853.33a6 6 0 0 1 6-6h148a6 6 0 0 1 6 6v188a6 6 0 0 1-6 6h-148a6 6 0 0 1-6-6zm16-6v200m128-200v200" stroke="#3a414a" fill="#edf5ff"/><use xlink:href="#a" transform="matrix(1,0,0,1,981.6666666666665,847.3333333333334) translate(18.086419753086417 65.77777777777777)"/><path d="M580 653.33a6 6 0 0 1 6-6h148a6 6 0 0 1 6 6v108a6 6 0 0 1-6 6H586a6 6 0 0 1-6-6zm16-6v120m128-120v120" stroke="#3a414a" fill="#fff7a1"/><use xlink:href="#b" transform="matrix(1,0,0,1,600,647.3333333333334) translate(24.845679012345684 64.44444444444444)"/><path d="M1330.45 653.13a7.8 7.8 0 0 1 7.55-5.8h116a4.6 4.6 0 0 1 4.45 5.8l-28.9 108.4a7.8 7.8 0 0 1-7.55 5.8h-116a4.6 4.6 0 0 1-4.45-5.8z" stroke="#3a414a" fill="#fff"/><use xlink:href="#c" transform="matrix(1,0,0,1,1305,652.3333333333334) translate(45.51117283950617 45.27777777777778)"/><use xlink:href="#d" transform="matrix(1,0,0,1,1305,652.3333333333334) translate(98.53586419753086 45.27777777777778)"/><use xlink:href="#e" transform="matrix(1,0,0,1,1305,652.3333333333334) translate(29.591419753086413 71.94444444444446)"/><path d="M820 653.33a6 6 0 0 1 6-6h148a6 6 0 0 1 6 6v108a6 6 0 0 1-6 6H826a6 6 0 0 1-6-6z" stroke="#3a414a" fill="#fff"/><use xlink:href="#f" transform="matrix(1,0,0,1,832,659.3333333333334) translate(21.76543209876543 53.77777777777778)"/><use xlink:href="#g" transform="matrix(1,0,0,1,832,659.3333333333334) translate(67.38271604938271 53.77777777777778)"/><path d="M741 707.33h62.12" stroke="#3a414a" fill="none"/><path d="M741 707.83h-.5v-1h.5z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M817.88 707.33l-14.26 4.64v-9.27z" stroke="#3a414a" fill="#3a414a"/><path d="M1060 493.33a6 6 0 0 1 6-6h148a6 6 0 0 1 6 6v108a6 6 0 0 1-6 6h-148a6 6 0 0 1-6-6zm16-6v120m128-120v120" stroke="#3a414a" fill="#fff3d9"/><use xlink:href="#h" transform="matrix(1,0,0,1,1080,487.33333333333337) translate(16.882716049382715 64.44444444444444)"/><path d="M1060 653.33a6 6 0 0 1 6-6h148a6 6 0 0 1 6 6v108a6 6 0 0 1-6 6h-148a6 6 0 0 1-6-6z" stroke="#3a414a" fill="#fff"/><use xlink:href="#i" transform="matrix(1,0,0,1,1072,659.3333333333334) translate(26.672839506172842 38.77777777777778)"/><use xlink:href="#j" transform="matrix(1,0,0,1,1072,659.3333333333334) translate(39.851851851851855 65.44444444444446)"/><path d="M1140 608.33v22.12" stroke="#3a414a" fill="none"/><path d="M1140.5 608.35h-1v-.52h1z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1140 645.2l-4.63-14.25h9.27z" stroke="#3a414a" fill="#3a414a"/><path d="M981 707.33h62.12" stroke="#3a414a" fill="none"/><path d="M981 707.83h-.5v-1h.5z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1057.88 707.33l-14.26 4.64v-9.27z" stroke="#3a414a" fill="#3a414a"/><path d="M1221 707.33h78.1" stroke="#3a414a" fill="none"/><path d="M1221 707.83h-.5v-1h.5z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1313.87 707.33l-14.27 4.64v-9.27z" stroke="#3a414a" fill="#3a414a"/><path d="M752.12 893.13a7.8 7.8 0 0 1 7.55-5.8h116a4.6 4.6 0 0 1 4.45 5.8l-28.9 108.4a7.8 7.8 0 0 1-7.55 5.8h-116a4.6 4.6 0 0 1-4.46-5.8z" stroke="#3a414a" fill="#fff"/><use xlink:href="#c" transform="matrix(1,0,0,1,726.6666666666665,892.3333333333334) translate(45.51117283950617 45.27777777777778)"/><use xlink:href="#d" transform="matrix(1,0,0,1,726.6666666666665,892.3333333333334) translate(98.53586419753086 45.27777777777778)"/><use xlink:href="#e" transform="matrix(1,0,0,1,726.6666666666665,892.3333333333334) translate(29.591419753086413 71.94444444444446)"/><path d="M867.18 945.33h10.05m10.04 0h20.1m10.04 0h20.1m10.04 0h20.1m10.03 0h20.1m10.03 0h20.1m10.04 0h20.1m10.03 0h20.1m10.03 0h20.1m10.04 0h20.1m10.03 0h20.1m10.03 0h10.05M867.18 949.33h10.05m10.04 0h20.1m10.04 0h20.1m10.04 0h20.1m10.03 0h20.1m10.03 0h20.1m10.04 0h20.1m10.03 0h20.1m10.03 0h20.1m10.04 0h20.1m10.03 0h20.1m10.03 0h10.05" stroke="#3a414a" stroke-width="2" fill="none"/><path d="M867.2 946.33h-.75l.53-2h.23zM867.2 950.33h-1.82l.54-2h1.3z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M1213.9 947.33l-14.25 4.64v-9.27z" stroke="#3a414a" stroke-width="2" fill="#3a414a"/><path d="M1232.12 893.13a7.8 7.8 0 0 1 7.55-5.8h116a4.6 4.6 0 0 1 4.45 5.8l-28.9 108.4a7.8 7.8 0 0 1-7.55 5.8h-116a4.6 4.6 0 0 1-4.46-5.8z" stroke="#3a414a" fill="#fff"/><use xlink:href="#k" transform="matrix(1,0,0,1,1206.6666666666665,892.3333333333334) translate(27.332160493827157 45.27777777777778)"/><use xlink:href="#l" transform="matrix(1,0,0,1,1206.6666666666665,892.3333333333334) translate(48.07907407407408 71.94444444444446)"/><path d="M1445.02 707.33h5.58m5.58 0h11.17m5.58 0h5.6l.93.08.9.23.88.36.8.48.72.6.6.73.5.8.36.88.22.9.08.95v5m0 5.02v10.02m0 5v10.03m0 5v10.03m0 5v10.02m0 5v10.03m0 5v10.03m0 5.02v10.02m0 5v10.03m0 5v10.02m0 5v10.02m0 5v10.03m0 5v10.03m0 5v10.02m0 5v10.03m0 5v10.03m0 5v10.03m0 5v10.02m0 5v10.02m0 5v10.03m0 5v10.03m0 5v10.03m0 5v10.02m0 5V1064m0 5v5.02l-.08.94-.22.9-.36.88-.5.8-.6.72-.72.6-.8.5-.87.37-.9.23-.95.07h-4.96m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.9m-4.97 0h-9.9m-4.98 0h-9.9m-4.97 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.93m-4.96 0h-9.9m-4.97 0h-9.92m-4.95 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.93m-4.96 0h-9.9m-4.97 0h-9.92m-4.95 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.9m-4.98 0h-9.9m-4.97 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.93m-4.96 0H804m-4.97 0h-9.92m-4.95 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.93m-4.96 0h-9.9m-4.97 0h-9.92m-4.95 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.92m-4.97 0h-9.9m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0h-9.92m-4.96 0H556l-.94-.07-.9-.22-.88-.35-.8-.5-.72-.6-.6-.72-.5-.8-.37-.88-.23-.9-.07-.95v-5.03m0-5.03v-10.05m0-5.04v-10.05m0-5.02v-10.06m0-5.03v-10.06m0-5.03v-10.04m0-5.03v-10.06m0-5.03V963.4m0-5.04v-5.03l.07-.94.22-.92.35-.87.5-.8.6-.7.72-.62.8-.5.88-.35.9-.22.95-.07h5.02m5.02 0h10.03m5.02 0h10.03m5 0h10.05m5.02 0h10.03m5.02 0h10.04m5 0h10.04m5.02 0h10.04m5 0h10.05m5.02 0h10.03m5.02 0h10.04m5.02 0h10.03m5.03 0h5.02" stroke="#3a414a" fill="none"/><path d="M1445.03 707.83h-.65l.27-1h.38zM737.02 947.83h-.38v-1h.64z" stroke="#3a414a" stroke-width=".05" fill="#3a414a"/><path d="M420 787.33v-314a6 6 0 0 1 6-6h35.67v320z" stroke="#3a414a" fill="#fff"/><path d="M461.67 1107.33H426a6 6 0 0 1-6-6v-314h41.67z" stroke="#3a414a" fill="#fff"/><path d="M461.67 467.33h1154a6 6 0 0 1 6 6v314h-1160zM1621.67 787.33v314a6 6 0 0 1-6 6h-1154v-320z" stroke="#3a414a" fill="none"/><g><use xlink:href="#m" transform="matrix(-1.8369701987210297e-16,-1,1,-1.8369701987210297e-16,419.99999999999994,787.3333333333335) translate(133.98765432098764 25.444444444444443)"/></g><g><use xlink:href="#n" transform="matrix(-1.8369701987210297e-16,-1,1,-1.8369701987210297e-16,419.99999999999994,1107.3333333333335) translate(122.25925925925927 25.444444444444443)"/></g><defs><path fill="#3a414a" d="M30-248c118-7 216 8 213 122C240-48 200 0 122 0H30v-248zM63-27c89 8 146-16 146-99s-60-101-146-95v194" id="o"/><path fill="#3a414a" d="M100-194c63 0 86 42 84 106H49c0 40 14 67 53 68 26 1 43-12 49-29l28 8c-11 28-37 45-77 45C44 4 14-33 15-96c1-61 26-98 85-98zm52 81c6-60-76-77-97-28-3 7-6 17-6 28h103" id="p"/><path fill="#3a414a" d="M96-169c-40 0-48 33-48 73s9 75 48 75c24 0 41-14 43-38l32 2c-6 37-31 61-74 61-59 0-76-41-82-99-10-93 101-131 147-64 4 7 5 14 7 22l-32 3c-4-21-16-35-41-35" id="q"/><path fill="#3a414a" d="M100-194c62-1 85 37 85 99 1 63-27 99-86 99S16-35 15-95c0-66 28-99 85-99zM99-20c44 1 53-31 53-75 0-43-8-75-51-75s-53 32-53 75 10 74 51 75" id="r"/><path fill="#3a414a" d="M85-194c31 0 48 13 60 33l-1-100h32l1 261h-30c-2-10 0-23-3-31C134-8 116 4 85 4 32 4 16-35 15-94c0-66 23-100 70-100zm9 24c-40 0-46 34-46 75 0 40 6 74 45 74 42 0 51-32 51-76 0-42-9-74-50-73" id="s"/><path fill="#3a414a" d="M114-163C36-179 61-72 57 0H25l-1-190h30c1 12-1 29 2 39 6-27 23-49 58-41v29" id="t"/><g id="a"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#o"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#p"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#q"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,39.44444444444444,0)" xlink:href="#r"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,51.79012345679012,0)" xlink:href="#s"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,64.1358024691358,0)" xlink:href="#p"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,76.48148148148148,0)" xlink:href="#t"/></g><path fill="#3a414a" d="M185-189c-5-48-123-54-124 2 14 75 158 14 163 119 3 78-121 87-175 55-17-10-28-26-33-46l33-7c5 56 141 63 141-1 0-78-155-14-162-118-5-82 145-84 179-34 5 7 8 16 11 25" id="u"/><path fill="#3a414a" d="M117-194c89-4 53 116 60 194h-32v-121c0-31-8-49-39-48C34-167 62-67 57 0H25l-1-190h30c1 10-1 24 2 32 11-22 29-35 61-36" id="v"/><path fill="#3a414a" d="M135-143c-3-34-86-38-87 0 15 53 115 12 119 90S17 21 10-45l28-5c4 36 97 45 98 0-10-56-113-15-118-90-4-57 82-63 122-42 12 7 21 19 24 35" id="w"/><g id="b"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#u"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.814814814814813,0)" xlink:href="#p"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,27.160493827160494,0)" xlink:href="#v"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,39.50617283950617,0)" xlink:href="#w"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,50.61728395061728,0)" xlink:href="#r"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,62.962962962962955,0)" xlink:href="#t"/></g><path fill="#3a414a" d="M141-36C126-15 110 5 73 4 37 3 15-17 15-53c-1-64 63-63 125-63 3-35-9-54-41-54-24 1-41 7-42 31l-33-3c5-37 33-52 76-52 45 0 72 20 72 64v82c-1 20 7 32 28 27v20c-31 9-61-2-59-35zM48-53c0 20 12 33 32 33 41-3 63-29 60-74-43 2-92-5-92 41" id="x"/><path fill="#3a414a" d="M59-47c-2 24 18 29 38 22v24C64 9 27 4 27-40v-127H5v-23h24l9-43h21v43h35v23H59v120" id="y"/><g id="c"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#o"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#x"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#y"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,34.50617283950617,0)" xlink:href="#x"/></g><path fill="#3a414a" d="M118-107v75H92v-75H18v-26h74v-75h26v75h74v26h-74" id="z"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#z" id="d"/><path fill="#3a414a" d="M197 0v-115H63V0H30v-248h33v105h134v-105h34V0h-34" id="A"/><g id="e"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#A"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#p"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#x"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,40.67901234567901,0)" xlink:href="#s"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,53.02469135802469,0)" xlink:href="#p"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,65.37037037037037,0)" xlink:href="#t"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,72.71604938271605,0)" xlink:href="#w"/></g><g id="f"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#A"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#x"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#w"/></g><g id="g"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#o"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#x"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#y"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,34.50617283950617,0)" xlink:href="#x"/></g><path fill="#3a414a" d="M205 0l-28-72H64L36 0H1l101-248h38L239 0h-34zm-38-99l-47-123c-12 45-31 82-46 123h93" id="B"/><path fill="#3a414a" d="M24 0v-261h32V0H24" id="C"/><g id="h"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#B"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.814814814814813,0)" xlink:href="#C"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,19.691358024691354,0)" xlink:href="#C"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,24.5679012345679,0)" xlink:href="#r"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,36.913580246913575,0)" xlink:href="#q"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,48.02469135802468,0)" xlink:href="#x"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,60.37037037037036,0)" xlink:href="#y"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,66.5432098765432,0)" xlink:href="#r"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,78.88888888888889,0)" xlink:href="#t"/></g><path fill="#3a414a" d="M233-177c-1 41-23 64-60 70L243 0h-38l-65-103H63V0H30v-248c88 3 205-21 203 71zM63-129c60-2 137 13 137-47 0-61-80-42-137-45v92" id="D"/><path fill="#3a414a" d="M145-31C134-9 116 4 85 4 32 4 16-35 15-94c0-59 17-99 70-100 32-1 48 14 60 33 0-11-1-24 2-32h30l-1 268h-32zM93-21c41 0 51-33 51-76s-8-73-50-73c-40 0-46 35-46 75s5 74 45 74" id="E"/><path fill="#3a414a" d="M84 4C-5 8 30-112 23-190h32v120c0 31 7 50 39 49 72-2 45-101 50-169h31l1 190h-30c-1-10 1-25-2-33-11 22-28 36-60 37" id="F"/><g id="i"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#D"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#p"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#E"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,40.67901234567901,0)" xlink:href="#F"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,53.02469135802469,0)" xlink:href="#p"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,65.37037037037037,0)" xlink:href="#w"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,76.48148148148148,0)" xlink:href="#y"/></g><path fill="#3a414a" d="M115-194c53 0 69 39 70 98 0 66-23 100-70 100C84 3 66-7 56-30L54 0H23l1-261h32v101c10-23 28-34 59-34zm-8 174c40 0 45-34 45-75 0-40-5-75-45-74-42 0-51 32-51 76 0 43 10 73 51 73" id="G"/><path fill="#3a414a" d="M101-234c-31-9-42 10-38 44h38v23H63V0H32v-167H5v-23h27c-7-52 17-82 69-68v24" id="H"/><g id="j"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#G"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,12.345679012345679,0)" xlink:href="#F"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,24.691358024691358,0)" xlink:href="#H"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,30.432098765432098,0)" xlink:href="#H"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,36.60493827160494,0)" xlink:href="#p"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,48.95061728395061,0)" xlink:href="#t"/></g><g id="k"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#u"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.814814814814813,0)" xlink:href="#y"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,20.98765432098765,0)" xlink:href="#t"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.33333333333333,0)" xlink:href="#F"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,40.679012345679006,0)" xlink:href="#q"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,51.79012345679011,0)" xlink:href="#y"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,57.962962962962955,0)" xlink:href="#F"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,70.30864197530863,0)" xlink:href="#t"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,77.65432098765432,0)" xlink:href="#p"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,90,0)" xlink:href="#s"/></g><g id="l"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#o"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#x"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#y"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,34.50617283950617,0)" xlink:href="#x"/></g><g id="m"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#D"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#p"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#x"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,40.67901234567901,0)" xlink:href="#s"/></g><g id="n"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#o"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#p"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#q"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,39.44444444444444,0)" xlink:href="#r"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,51.79012345679012,0)" xlink:href="#s"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,64.1358024691358,0)" xlink:href="#p"/></g></defs></g></svg> \ No newline at end of file
diff --git a/seed/0119-pw-sensor/high-level-view.svg b/seed/0119-pw-sensor/high-level-view.svg
new file mode 100644
index 000000000..63e966fbc
--- /dev/null
+++ b/seed/0119-pw-sensor/high-level-view.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:lucid="lucid" width="962.67" height="781"><g transform="translate(-137.83333333333334 -199.5)" lucid:page-tab-id="QS0QVPe9s7im"><path d="M0 0h1500v1000H0z" fill="#fff"/><path d="M161 522a1 1 0 0 1 1-1h796a1 1 0 0 1 1 1 1 1 0 0 1-1 1H162a1 1 0 0 1-1-1z" fill="none"/><path d="M202.82 521h40.82m20.4 0h40.83m20.4 0h40.83m20.4 0h40.83m20.4 0h40.83m20.4 0h40.83m20.4 0h40.83m20.4 0h40.83m20.4 0h40.83m20.4 0h40.82m20.4 0h40.83m20.4 0h40.83m20.4 0H958.17l.15.05.15.06.14.1.1.1.1.1.1.15.05.14.04.14v.32l-.05.15-.06.15-.1.14-.1.1-.1.1-.15.1-.14.05-.14.04H937.6m-20.42 0h-40.82m-20.4 0h-40.83m-20.4 0H753.9m-20.4 0h-40.83m-20.4 0h-40.83m-20.4 0H570.2m-20.4 0h-40.83m-20.4 0h-40.83m-20.4 0H386.5m-20.4 0h-40.82m-20.4 0h-40.83m-20.4 0H202.8m-20.4 0H161.83l-.15-.05-.15-.06-.14-.1-.1-.1-.1-.1-.1-.15-.05-.14-.04-.14v-.32l.05-.15.06-.15.1-.14.1-.1.1-.1.15-.1.14-.05.14-.04h20.56" stroke="#3a414a" stroke-width="2" fill="none"/><path d="M340 246a6 6 0 0 1 6-6h148a6 6 0 0 1 6 6v108a6 6 0 0 1-6 6H346a6 6 0 0 1-6-6z" stroke="#3a414a" fill="#c3f7c8"/><use xlink:href="#a" transform="matrix(1,0,0,1,352,252) translate(10.098765432098766 53.77777777777778)"/><use xlink:href="#b" transform="matrix(1,0,0,1,352,252) translate(72.87654320987654 53.77777777777778)"/><path d="M620 246a6 6 0 0 1 6-6h148a6 6 0 0 1 6 6v108a6 6 0 0 1-6 6H626a6 6 0 0 1-6-6z" stroke="#3a414a" fill="#c3f7c8"/><use xlink:href="#a" transform="matrix(1,0,0,1,632,252) translate(10.098765432098766 53.77777777777778)"/><use xlink:href="#b" transform="matrix(1,0,0,1,632,252) translate(72.87654320987654 53.77777777777778)"/><path d="M340 466a6 6 0 0 1 6-6h148a6 6 0 0 1 6 6v108a6 6 0 0 1-6 6H346a6 6 0 0 1-6-6z" stroke="#3a414a" fill="#d7faf5"/><path d="M356 460v120m128-120v120" stroke="#3a414a" fill="none"/><use xlink:href="#c" transform="matrix(1,0,0,1,365,465) translate(-1.1111111111111143 59.44444444444444)"/><path d="M620 466a6 6 0 0 1 6-6h148a6 6 0 0 1 6 6v108a6 6 0 0 1-6 6H626a6 6 0 0 1-6-6z" stroke="#3a414a" fill="#d7faf5"/><path d="M636 460v120m128-120v120" stroke="#3a414a" fill="none"/><use xlink:href="#c" transform="matrix(1,0,0,1,645,465) translate(-1.1111111111111143 59.44444444444444)"/><path d="M420 390.88v67.7" stroke="#3a414a" fill="none"/><path d="M420 361.2l14.85 14.86L420 391.2l-14.85-15.14z" stroke="#3a414a" fill="#3a414a"/><path d="M409.82 441.3L420 458.52l10.18-17.22M700 390.88v67.7" stroke="#3a414a" fill="none"/><path d="M700 361.2l14.85 14.86L700 391.2l-14.85-15.14z" stroke="#3a414a" fill="#3a414a"/><path d="M689.82 441.3L700 458.52l10.18-17.22" stroke="#3a414a" fill="none"/><path d="M166 460a6 6 0 0 1-6-6V226a6 6 0 0 1 6-6h48a6 6 0 0 1 6 6v228a6 6 0 0 1-6 6z" stroke="#000" stroke-opacity="0" fill="#fff" fill-opacity="0"/><use xlink:href="#d" transform="matrix(6.123233995736766e-17,-1,1,6.123233995736766e-17,165,455) translate(17.65432098765433 30.27777777777778)"/><use xlink:href="#e" transform="matrix(6.123233995736766e-17,-1,1,6.123233995736766e-17,165,455) translate(132.28395061728395 30.27777777777778)"/><use xlink:href="#f" transform="matrix(6.123233995736766e-17,-1,1,6.123233995736766e-17,165,455) translate(144.62962962962965 30.27777777777778)"/><path d="M164.33 840a6 6 0 0 1-6-6V606a6 6 0 0 1 6-6h51.34a6 6 0 0 1 6 6v228a6 6 0 0 1-6 6z" stroke="#000" stroke-opacity="0" fill="#fff" fill-opacity="0"/><use xlink:href="#g" transform="matrix(6.123233995736766e-17,-1,1,6.123233995736766e-17,163.33333333333337,835.0000000000001) translate(34.228395061728406 21.15277777777778)"/><use xlink:href="#h" transform="matrix(6.123233995736766e-17,-1,1,6.123233995736766e-17,163.33333333333337,835.0000000000001) translate(125.46296296296296 21.15277777777778)"/><use xlink:href="#i" transform="matrix(6.123233995736766e-17,-1,1,6.123233995736766e-17,163.33333333333337,835.0000000000001) translate(59.59876543209876 47.81944444444444)"/><path d="M343.33 685a3.2 3.2 0 0 1 2.67-5h148a3.2 3.2 0 0 1 2.67 5l-73.34 110a4 4 0 0 1-6.66 0z" stroke="#1071e5" stroke-width="2" fill="#fff"/><use xlink:href="#j" transform="matrix(1,0,0,1,345,685) translate(9.074074074074062 46.111111111111114)"/><use xlink:href="#k" transform="matrix(1,0,0,1,345,685) translate(54.04320987654321 72.77777777777777)"/><path d="M420 581.5v79" stroke="#1071e5" stroke-width="2" fill="none"/><path d="M421 581.53h-2v-1.03h2z" stroke="#1071e5" stroke-width=".05" fill="#1071e5"/><path d="M420 675.76l-4.63-14.26h9.26z" stroke="#1071e5" stroke-width="2" fill="#1071e5"/><path d="M641.33 581.5V634a6 6 0 0 1-6 6H465a6 6 0 0 0-6 6v14.5" stroke="#1071e5" stroke-width="2" fill="none"/><path d="M642.33 581.53h-2v-1.03h2z" stroke="#1071e5" stroke-width=".05" fill="#1071e5"/><path d="M459 675.76l-4.65-14.26h9.27z" stroke="#1071e5" stroke-width="2" fill="#1071e5"/><path d="M480 826a6 6 0 0 1 6-6h148a6 6 0 0 1 6 6v108a6 6 0 0 1-6 6H486a6 6 0 0 1-6-6zm16-6v120m128-120v120" stroke="#3a414a" fill="#fff7a1"/><use xlink:href="#l" transform="matrix(1,0,0,1,500,820) translate(24.845679012345684 64.44444444444444)"/><path d="M421 873.96l.06.82.2.76.3.73.4.67.5.6.6.5.67.4.73.3.76.2.82.06H461v2h-35.04l-1.06-.08-1.06-.26-1.02-.42-.94-.57-.83-.72-.72-.83-.57-.94-.42-1.02-.26-1.06-.08-1.06v-20.96h2zm0-42.2h-2v-32.97h2z" stroke="#1071e5" stroke-width=".05" fill="#1071e5"/><path d="M419.02 797.7l.98.1.98-.1.02 1.12h-2v-1.13z" fill="#1071e5"/><path d="M419.03 797.67l.97.1 1-.1.02 1.17h-2.04v-1.18zm0 1.12h1.94l-.02-1.07-.95.1-.98-.1z" stroke="#1071e5" stroke-width=".05" fill="#1071e5"/><path d="M476.26 880L462 884.63v-9.26z" fill="#1071e5"/><path d="M479.5 880l-18.5 6v-12zm-16.5 3.26l10.03-3.26-10.03-3.26z" stroke="#1071e5" stroke-width=".05" fill="#1071e5"/><use xlink:href="#m" transform="matrix(1,0,0,1,361.95059513097374,831.7486908605974) translate(0 14.222222222222223)"/><path d="M623.33 685a3.2 3.2 0 0 1 2.67-5h148a3.2 3.2 0 0 1 2.67 5l-73.34 110a4 4 0 0 1-6.66 0z" stroke="#e81313" stroke-width="2" fill="#fff"/><use xlink:href="#n" transform="matrix(1,0,0,1,625,685) translate(51.57907407407407 28.09027777777778)"/><use xlink:href="#o" transform="matrix(1,0,0,1,625,685) translate(41.702530864197534 54.75694444444445)"/><path d="M701 874.04l-.08 1.06-.26 1.06-.42 1.02-.57.94-.72.83-.83.72-.94.57-1.02.42-1.06.26-1.06.08H641.5v-2h52.46l.82-.07.76-.18.73-.3.67-.4.6-.52.5-.6.4-.66.3-.73.2-.76.06-.82V851h2zm0-44.37h-2V816.3h2z" stroke="#e81313" stroke-width=".05" fill="#e81313"/><path d="M641.53 881h-1.03v-2h1.03z" fill="#e81313"/><path d="M641.55 881.02h-1.07V879h1.07zm-1.02-2V881h.97V879z" stroke="#e81313" stroke-width=".05" fill="#e81313"/><path d="M704.63 815.3h-9.26l4.63-14.27z" fill="#e81313"/><path d="M706 816.3h-12l6-18.5zm-9.26-2h6.52L700 804.27z" stroke="#e81313" stroke-width=".05" fill="#e81313"/><use xlink:href="#p" transform="matrix(1,0,0,1,680.7901234567901,829.6747850963222) translate(0 14.222222222222223)"/><path d="M700 678v-79" stroke="#e81313" stroke-width="2" fill="none"/><path d="M701 679h-2v-1.03h2z" stroke="#e81313" stroke-width=".05" fill="#e81313"/><path d="M700 583.74l4.63 14.26h-9.26z" stroke="#e81313" stroke-width="2" fill="#e81313"/><path d="M662.36 678v-52a6 6 0 0 0-6-6H487.33a6 6 0 0 1-6-6v-15" stroke="#e81313" stroke-width="2" fill="none"/><path d="M663.36 679h-2v-1.03h2z" stroke="#e81313" stroke-width=".05" fill="#e81313"/><path d="M481.33 583.74l4.64 14.26h-9.27z" stroke="#e81313" stroke-width="2" fill="#e81313"/><path d="M760 800h288l32 32v128H760z" stroke="#3a414a" fill="#fff"/><path d="M1048 800.48V832h31.52" stroke="#3a414a" fill="#fff"/><g><use xlink:href="#q" transform="matrix(1,0,0,1,765,805) translate(0 27.15277777777778)"/><use xlink:href="#r" transform="matrix(1,0,0,1,765,805) translate(19.753086419753085 27.15277777777778)"/><use xlink:href="#s" transform="matrix(1,0,0,1,765,805) translate(96.23456790123456 27.15277777777778)"/><use xlink:href="#t" transform="matrix(1,0,0,1,765,805) translate(155.4320987654321 27.15277777777778)"/><use xlink:href="#u" transform="matrix(1,0,0,1,765,805) translate(0 53.81944444444445)"/><use xlink:href="#v" transform="matrix(1,0,0,1,765,805) translate(133.08641975308643 53.81944444444445)"/><use xlink:href="#w" transform="matrix(1,0,0,1,765,805) translate(167.5925925925926 53.81944444444445)"/><use xlink:href="#x" transform="matrix(1,0,0,1,765,805) translate(204.62962962962965 53.81944444444445)"/><use xlink:href="#y" transform="matrix(1,0,0,1,765,805) translate(0 80.48611111111111)"/><use xlink:href="#z" transform="matrix(1,0,0,1,765,805) translate(41.97530864197531 80.48611111111111)"/><use xlink:href="#A" transform="matrix(1,0,0,1,765,805) translate(101.23456790123458 80.48611111111111)"/><use xlink:href="#B" transform="matrix(1,0,0,1,765,805) translate(127.09876543209879 80.48611111111111)"/><use xlink:href="#C" transform="matrix(1,0,0,1,765,805) translate(166.48148148148152 80.48611111111111)"/><use xlink:href="#D" transform="matrix(1,0,0,1,765,805) translate(185.00000000000006 80.48611111111111)"/><use xlink:href="#E" transform="matrix(1,0,0,1,765,805) translate(246.54320987654327 80.48611111111111)"/><use xlink:href="#F" transform="matrix(1,0,0,1,765,805) translate(0 107.1527777777778)"/><use xlink:href="#u" transform="matrix(1,0,0,1,765,805) translate(78.88888888888887 107.1527777777778)"/><use xlink:href="#G" transform="matrix(1,0,0,1,765,805) translate(211.9753086419753 107.1527777777778)"/><use xlink:href="#H" transform="matrix(1,0,0,1,765,805) translate(235.37037037037035 107.1527777777778)"/><use xlink:href="#I" transform="matrix(1,0,0,1,765,805) translate(0 133.81944444444446)"/><use xlink:href="#J" transform="matrix(1,0,0,1,765,805) translate(108.4567901234568 133.81944444444446)"/></g><defs><path fill="#3a414a" d="M212-179c-10-28-35-45-73-45-59 0-87 40-87 99 0 60 29 101 89 101 43 0 62-24 78-52l27 14C228-24 195 4 139 4 59 4 22-46 18-125c-6-104 99-153 187-111 19 9 31 26 39 46" id="K"/><path fill="#3a414a" d="M24 0v-261h32V0H24" id="L"/><path fill="#3a414a" d="M24-231v-30h32v30H24zM24 0v-190h32V0H24" id="M"/><path fill="#3a414a" d="M100-194c63 0 86 42 84 106H49c0 40 14 67 53 68 26 1 43-12 49-29l28 8c-11 28-37 45-77 45C44 4 14-33 15-96c1-61 26-98 85-98zm52 81c6-60-76-77-97-28-3 7-6 17-6 28h103" id="N"/><path fill="#3a414a" d="M117-194c89-4 53 116 60 194h-32v-121c0-31-8-49-39-48C34-167 62-67 57 0H25l-1-190h30c1 10-1 24 2 32 11-22 29-35 61-36" id="O"/><path fill="#3a414a" d="M59-47c-2 24 18 29 38 22v24C64 9 27 4 27-40v-127H5v-23h24l9-43h21v43h35v23H59v120" id="P"/><g id="a"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#K"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#L"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,20.864197530864196,0)" xlink:href="#M"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,25.74074074074074,0)" xlink:href="#N"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,38.08641975308642,0)" xlink:href="#O"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,50.432098765432094,0)" xlink:href="#P"/></g><path fill="#3a414a" d="M100-194c62-1 85 37 85 99 1 63-27 99-86 99S16-35 15-95c0-66 28-99 85-99zM99-20c44 1 53-31 53-75 0-43-8-75-51-75s-53 32-53 75 10 74 51 75" id="Q"/><path fill="#3a414a" d="M85-194c31 0 48 13 60 33l-1-100h32l1 261h-30c-2-10 0-23-3-31C134-8 116 4 85 4 32 4 16-35 15-94c0-66 23-100 70-100zm9 24c-40 0-46 34-46 75 0 40 6 74 45 74 42 0 51-32 51-76 0-42-9-74-50-73" id="R"/><g id="b"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#K"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#Q"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#R"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,40.67901234567901,0)" xlink:href="#N"/></g><path fill="#3a414a" d="M96-169c-40 0-48 33-48 73s9 75 48 75c24 0 41-14 43-38l32 2c-6 37-31 61-74 61-59 0-76-41-82-99-10-93 101-131 147-64 4 7 5 14 7 22l-32 3c-4-21-16-35-41-35" id="S"/><g id="c"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#K"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#Q"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#O"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,40.67901234567901,0)" xlink:href="#O"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,53.02469135802469,0)" xlink:href="#N"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,65.37037037037037,0)" xlink:href="#S"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,76.48148148148148,0)" xlink:href="#P"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,82.65432098765432,0)" xlink:href="#M"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,87.53086419753086,0)" xlink:href="#Q"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,99.87654320987654,0)" xlink:href="#O"/></g><path fill="#3a414a" d="M205 0l-28-72H64L36 0H1l101-248h38L239 0h-34zm-38-99l-47-123c-12 45-31 82-46 123h93" id="T"/><path fill="#3a414a" d="M115-194c55 1 70 41 70 98S169 2 115 4C84 4 66-9 55-30l1 105H24l-1-265h31l2 30c10-21 28-34 59-34zm-8 174c40 0 45-34 45-75s-6-73-45-74c-42 0-51 32-51 76 0 43 10 73 51 73" id="U"/><path fill="#3a414a" d="M141-36C126-15 110 5 73 4 37 3 15-17 15-53c-1-64 63-63 125-63 3-35-9-54-41-54-24 1-41 7-42 31l-33-3c5-37 33-52 76-52 45 0 72 20 72 64v82c-1 20 7 32 28 27v20c-31 9-61-2-59-35zM48-53c0 20 12 33 32 33 41-3 63-29 60-74-43 2-92-5-92 41" id="V"/><g id="d"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#T"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.814814814814813,0)" xlink:href="#U"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,27.160493827160494,0)" xlink:href="#U"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,39.50617283950617,0)" xlink:href="#L"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,44.382716049382715,0)" xlink:href="#M"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,49.25925925925926,0)" xlink:href="#S"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,60.37037037037037,0)" xlink:href="#V"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,72.71604938271605,0)" xlink:href="#P"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,78.88888888888889,0)" xlink:href="#M"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,83.76543209876543,0)" xlink:href="#Q"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,96.11111111111111,0)" xlink:href="#O"/></g><path fill="#3a414a" d="M0 4l72-265h28L28 4H0" id="W"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#W" id="e"/><path fill="#3a414a" d="M30 0v-248h33v221h125V0H30" id="X"/><path fill="#3a414a" d="M115-194c53 0 69 39 70 98 0 66-23 100-70 100C84 3 66-7 56-30L54 0H23l1-261h32v101c10-23 28-34 59-34zm-8 174c40 0 45-34 45-75 0-40-5-75-45-74-42 0-51 32-51 76 0 43 10 73 51 73" id="Y"/><path fill="#3a414a" d="M114-163C36-179 61-72 57 0H25l-1-190h30c1 12-1 29 2 39 6-27 23-49 58-41v29" id="Z"/><path fill="#3a414a" d="M179-190L93 31C79 59 56 82 12 73V49c39 6 53-20 64-50L1-190h34L92-34l54-156h33" id="aa"/><g id="f"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#X"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,12.345679012345679,0)" xlink:href="#M"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,17.22222222222222,0)" xlink:href="#Y"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,29.5679012345679,0)" xlink:href="#Z"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,36.913580246913575,0)" xlink:href="#V"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,49.25925925925925,0)" xlink:href="#Z"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,56.60493827160493,0)" xlink:href="#aa"/></g><path fill="#3a414a" d="M30-248c87 1 191-15 191 75 0 78-77 80-158 76V0H30v-248zm33 125c57 0 124 11 124-50 0-59-68-47-124-48v98" id="ab"/><path fill="#3a414a" d="M177-190C167-65 218 103 67 71c-23-6-38-20-44-43l32-5c15 47 100 32 89-28v-30C133-14 115 1 83 1 29 1 15-40 15-95c0-56 16-97 71-98 29-1 48 16 59 35 1-10 0-23 2-32h30zM94-22c36 0 50-32 50-73 0-42-14-75-50-75-39 0-46 34-46 75s6 73 46 73" id="ac"/><path fill="#3a414a" d="M206 0h-36l-40-164L89 0H53L-1-190h32L70-26l43-164h34l41 164 42-164h31" id="ad"/><g id="g"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#ab"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.814814814814813,0)" xlink:href="#M"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,19.691358024691354,0)" xlink:href="#ac"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,32.03703703703703,0)" xlink:href="#ad"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,48.02469135802468,0)" xlink:href="#N"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,60.37037037037036,0)" xlink:href="#N"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,72.71604938271604,0)" xlink:href="#R"/></g><path fill="#3a414a" d="M185-189c-5-48-123-54-124 2 14 75 158 14 163 119 3 78-121 87-175 55-17-10-28-26-33-46l33-7c5 56 141 63 141-1 0-78-155-14-162-118-5-82 145-84 179-34 5 7 8 16 11 25" id="ae"/><path fill="#3a414a" d="M135-143c-3-34-86-38-87 0 15 53 115 12 119 90S17 21 10-45l28-5c4 36 97 45 98 0-10-56-113-15-118-90-4-57 82-63 122-42 12 7 21 19 24 35" id="af"/><g id="h"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#ae"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.814814814814813,0)" xlink:href="#N"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,27.160493827160494,0)" xlink:href="#O"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,39.50617283950617,0)" xlink:href="#af"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,50.61728395061728,0)" xlink:href="#Q"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,62.962962962962955,0)" xlink:href="#Z"/></g><path fill="#3a414a" d="M63-220v92h138v28H63V0H30v-248h175v28H63" id="ag"/><path fill="#3a414a" d="M210-169c-67 3-38 105-44 169h-31v-121c0-29-5-50-35-48C34-165 62-65 56 0H25l-1-190h30c1 10-1 24 2 32 10-44 99-50 107 0 11-21 27-35 58-36 85-2 47 119 55 194h-31v-121c0-29-5-49-35-48" id="ah"/><path fill="#3a414a" d="M143 0L79-87 56-68V0H24v-261h32v163l83-92h37l-77 82L181 0h-38" id="ai"/><g id="i"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#ag"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,13.518518518518517,0)" xlink:href="#Z"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,20.864197530864196,0)" xlink:href="#V"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,33.20987654320987,0)" xlink:href="#ah"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,51.66666666666666,0)" xlink:href="#N"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,64.01234567901234,0)" xlink:href="#ad"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,80,0)" xlink:href="#Q"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,92.34567901234568,0)" xlink:href="#Z"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,99.69135802469137,0)" xlink:href="#ai"/></g><path fill="#3a414a" d="M101-234c-31-9-42 10-38 44h38v23H63V0H32v-167H5v-23h27c-7-52 17-82 69-68v24" id="aj"/><path fill="#3a414a" d="M84 4C-5 8 30-112 23-190h32v120c0 31 7 50 39 49 72-2 45-101 50-169h31l1 190h-30c-1-10 1-25-2-33-11 22-28 36-60 37" id="ak"/><g id="j"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#K"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#Q"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#O"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,40.67901234567901,0)" xlink:href="#aj"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,46.851851851851855,0)" xlink:href="#M"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,51.7283950617284,0)" xlink:href="#ac"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,64.07407407407408,0)" xlink:href="#ak"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,76.41975308641976,0)" xlink:href="#Z"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,83.76543209876544,0)" xlink:href="#V"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,96.11111111111113,0)" xlink:href="#P"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,102.28395061728396,0)" xlink:href="#M"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,107.16049382716051,0)" xlink:href="#Q"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,119.50617283950619,0)" xlink:href="#O"/></g><path fill="#3a414a" d="M141 0L90-78 38 0H4l68-98-65-92h35l48 74 47-74h35l-64 92 68 98h-35" id="al"/><g id="k"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#ah"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,18.456790123456788,0)" xlink:href="#ak"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,30.80246913580247,0)" xlink:href="#al"/></g><g id="l"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#ae"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.814814814814813,0)" xlink:href="#N"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,27.160493827160494,0)" xlink:href="#O"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,39.50617283950617,0)" xlink:href="#af"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,50.61728395061728,0)" xlink:href="#Q"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,62.962962962962955,0)" xlink:href="#Z"/></g><path fill="#333" d="M67-125c0 53 21 87 73 88 37 1 54-22 65-47l45 17C233-25 199 4 140 4 58 4 20-42 15-125 8-235 124-281 211-232c18 10 29 29 36 50l-46 12c-8-25-30-41-62-41-52 0-71 34-72 86" id="am"/><path fill="#333" d="M110-194c64 0 96 36 96 99 0 64-35 99-97 99-61 0-95-36-95-99 0-62 34-99 96-99zm-1 164c35 0 45-28 45-65 0-40-10-65-43-65-34 0-45 26-45 65 0 36 10 65 43 65" id="an"/><path fill="#333" d="M135-194c87-1 58 113 63 194h-50c-7-57 23-157-34-157-59 0-34 97-39 157H25l-1-190h47c2 12-1 28 3 38 12-26 28-41 61-42" id="ao"/><path fill="#333" d="M121-226c-27-7-43 5-38 36h38v33H83V0H34v-157H6v-33h28c-9-59 32-81 87-68v32" id="ap"/><path fill="#333" d="M25-224v-37h50v37H25zM25 0v-190h50V0H25" id="aq"/><path fill="#333" d="M195-6C206 82 75 100 31 46c-4-6-6-13-8-21l49-6c3 16 16 24 34 25 40 0 42-37 40-79-11 22-30 35-61 35-53 0-70-43-70-97 0-56 18-96 73-97 30 0 46 14 59 34l2-30h47zm-90-29c32 0 41-27 41-63 0-35-9-62-40-62-32 0-39 29-40 63 0 36 9 62 39 62" id="ar"/><path fill="#333" d="M85 4C-2 5 27-109 22-190h50c7 57-23 150 33 157 60-5 35-97 40-157h50l1 190h-47c-2-12 1-28-3-38-12 25-28 42-61 42" id="as"/><path fill="#333" d="M135-150c-39-12-60 13-60 57V0H25l-1-190h47c2 13-1 29 3 40 6-28 27-53 61-41v41" id="at"/><path fill="#333" d="M133-34C117-15 103 5 69 4 32 3 11-16 11-54c-1-60 55-63 116-61 1-26-3-47-28-47-18 1-26 9-28 27l-52-2c7-38 36-58 82-57s74 22 75 68l1 82c-1 14 12 18 25 15v27c-30 8-71 5-69-32zm-48 3c29 0 43-24 42-57-32 0-66-3-65 30 0 17 8 27 23 27" id="au"/><path fill="#333" d="M115-3C79 11 28 4 28-45v-112H4v-33h27l15-45h31v45h36v33H77v99c-1 23 16 31 38 25v30" id="av"/><g id="m"><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,0,0)" xlink:href="#am"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,12.790123456790125,0)" xlink:href="#an"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,23.60493827160494,0)" xlink:href="#ao"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,34.41975308641975,0)" xlink:href="#ap"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,40.2962962962963,0)" xlink:href="#aq"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,45.23456790123457,0)" xlink:href="#ar"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,56.04938271604939,0)" xlink:href="#as"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,66.8641975308642,0)" xlink:href="#at"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,73.77777777777779,0)" xlink:href="#au"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,83.65432098765433,0)" xlink:href="#av"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,89.53086419753087,0)" xlink:href="#aq"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,94.46913580246914,0)" xlink:href="#an"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,105.28395061728396,0)" xlink:href="#ao"/></g><path fill="#3a414a" d="M30-248c118-7 216 8 213 122C240-48 200 0 122 0H30v-248zM63-27c89 8 146-16 146-99s-60-101-146-95v194" id="aw"/><g id="n"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#aw"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#V"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333332,0)" xlink:href="#P"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,34.50617283950617,0)" xlink:href="#V"/></g><g id="o"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#R"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,12.345679012345679,0)" xlink:href="#N"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,24.691358024691358,0)" xlink:href="#ah"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,43.148148148148145,0)" xlink:href="#ak"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,55.49382716049382,0)" xlink:href="#al"/></g><path fill="#333" d="M24-248c120-7 223 5 221 122C244-46 201 0 124 0H24v-248zM76-40c74 7 117-18 117-86 0-67-45-88-117-82v168" id="ax"/><g id="p"><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,0,0)" xlink:href="#ax"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,12.790123456790125,0)" xlink:href="#au"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,22.66666666666667,0)" xlink:href="#av"/><use transform="matrix(0.04938271604938272,0,0,0.04938271604938272,28.54320987654322,0)" xlink:href="#au"/></g><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#T" id="q"/><g id="r"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#ae"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.814814814814813,0)" xlink:href="#N"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,27.160493827160494,0)" xlink:href="#O"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,39.50617283950617,0)" xlink:href="#af"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,50.61728395061728,0)" xlink:href="#Q"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,62.962962962962955,0)" xlink:href="#Z"/></g><g id="s"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#S"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,11.11111111111111,0)" xlink:href="#Q"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,23.45679012345679,0)" xlink:href="#ak"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,35.80246913580247,0)" xlink:href="#L"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,40.67901234567901,0)" xlink:href="#R"/></g><g id="t"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#Y"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,12.345679012345679,0)" xlink:href="#N"/></g><g id="u"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#M"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,4.876543209876543,0)" xlink:href="#ah"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,23.33333333333333,0)" xlink:href="#U"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,35.679012345679006,0)" xlink:href="#L"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,40.55555555555555,0)" xlink:href="#N"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,52.90123456790123,0)" xlink:href="#ah"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,71.35802469135801,0)" xlink:href="#N"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,83.7037037037037,0)" xlink:href="#O"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,96.04938271604938,0)" xlink:href="#P"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,102.22222222222221,0)" xlink:href="#N"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,114.5679012345679,0)" xlink:href="#R"/></g><path fill="#3a414a" d="M108 0H70L1-190h34L89-25l56-165h34" id="ay"/><g id="v"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#ay"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,11.11111111111111,0)" xlink:href="#M"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.987654320987653,0)" xlink:href="#V"/></g><path fill="#3a414a" d="M106-169C34-169 62-67 57 0H25v-261h32l-1 103c12-21 28-36 61-36 89 0 53 116 60 194h-32v-121c2-32-8-49-39-48" id="az"/><g id="w"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#P"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,6.172839506172839,0)" xlink:href="#az"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,18.51851851851852,0)" xlink:href="#N"/></g><g id="x"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#ab"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.814814814814813,0)" xlink:href="#M"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,19.691358024691354,0)" xlink:href="#ac"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,32.03703703703703,0)" xlink:href="#ad"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,48.02469135802468,0)" xlink:href="#N"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,60.37037037037036,0)" xlink:href="#N"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,72.71604938271604,0)" xlink:href="#R"/></g><g id="y"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#Y"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,12.345679012345679,0)" xlink:href="#ak"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,24.691358024691358,0)" xlink:href="#af"/></g><path fill="#3a414a" d="M33 0v-248h34V0H33" id="aA"/><path fill="#3a414a" d="M68-38c1 34 0 65-14 84H32c9-13 17-26 17-46H33v-38h35" id="aB"/><g id="z"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#T"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,14.814814814814813,0)" xlink:href="#ab"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,29.629629629629626,0)" xlink:href="#aA"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,35.80246913580247,0)" xlink:href="#af"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,46.91358024691358,0)" xlink:href="#aB"/></g><g id="A"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#Q"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,12.345679012345679,0)" xlink:href="#Z"/></g><g id="B"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#S"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,11.11111111111111,0)" xlink:href="#V"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,23.45679012345679,0)" xlink:href="#L"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.333333333333336,0)" xlink:href="#L"/></g><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#V" id="C"/><g id="D"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#R"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,12.345679012345679,0)" xlink:href="#Z"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,19.691358024691358,0)" xlink:href="#M"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,24.5679012345679,0)" xlink:href="#ay"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,35.67901234567901,0)" xlink:href="#N"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,48.02469135802469,0)" xlink:href="#Z"/></g><path fill="#3a414a" d="M47-170H22l-4-78h33" id="aC"/><g id="E"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#P"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,6.172839506172839,0)" xlink:href="#az"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,18.51851851851852,0)" xlink:href="#V"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,30.864197530864196,0)" xlink:href="#P"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,37.03703703703704,0)" xlink:href="#aC"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,41.23456790123457,0)" xlink:href="#af"/></g><g id="F"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#V"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,12.345679012345679,0)" xlink:href="#L"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,17.22222222222222,0)" xlink:href="#Z"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,24.5679012345679,0)" xlink:href="#N"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,36.913580246913575,0)" xlink:href="#V"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,49.25925925925925,0)" xlink:href="#R"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,61.60493827160493,0)" xlink:href="#aa"/></g><g id="G"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#M"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,4.876543209876543,0)" xlink:href="#O"/></g><g id="H"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#P"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,6.172839506172839,0)" xlink:href="#az"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,18.51851851851852,0)" xlink:href="#N"/></g><g id="I"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#ak"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,12.345679012345679,0)" xlink:href="#O"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,24.691358024691358,0)" xlink:href="#R"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,37.03703703703704,0)" xlink:href="#N"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,49.382716049382715,0)" xlink:href="#Z"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,56.72839506172839,0)" xlink:href="#L"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,61.60493827160494,0)" xlink:href="#aa"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,72.71604938271605,0)" xlink:href="#M"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,77.5925925925926,0)" xlink:href="#O"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,89.93827160493828,0)" xlink:href="#ac"/></g><path fill="#3a414a" d="M233-177c-1 41-23 64-60 70L243 0h-38l-65-103H63V0H30v-248c88 3 205-21 203 71zM63-129c60-2 137 13 137-47 0-61-80-42-137-45v92" id="aD"/><path fill="#3a414a" d="M127-220V0H93v-220H8v-28h204v28h-85" id="aE"/><path fill="#3a414a" d="M140-251c81 0 123 46 123 126C263-46 219 4 140 4 59 4 17-45 17-125s42-126 123-126zm0 227c63 0 89-41 89-101s-29-99-89-99c-61 0-89 39-89 99S79-25 140-24" id="aF"/><g id="J"><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,0,0)" xlink:href="#aD"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,15.555555555555555,0)" xlink:href="#aE"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,28.641975308641975,0)" xlink:href="#aF"/><use transform="matrix(0.06172839506172839,0,0,0.06172839506172839,45.925925925925924,0)" xlink:href="#ae"/></g></defs></g></svg> \ No newline at end of file
diff --git a/seed/0122-code-samples.rst b/seed/0122-code-samples.rst
new file mode 100644
index 000000000..294f325f2
--- /dev/null
+++ b/seed/0122-code-samples.rst
@@ -0,0 +1,211 @@
+.. _seed-0122:
+
+===================================
+0122: Organize Pigweed code samples
+===================================
+.. seed::
+ :number: 122
+ :name: Organize Pigweed code samples
+ :status: accepted
+ :proposal_date: 2024-01-09
+ :cl: 187121
+ :authors: Ted Pudlik
+ :facilitator: Kayce Basques
+
+-------
+Summary
+-------
+This SEED describes how Pigweed code samples will be organized. Implementation
+bug: https://pwbug.dev//322816792.
+
+----------
+Motivation
+----------
+Pigweed users need to see code samples that demonstrate Pigweed in action.
+However, there are a few different use cases for such code samples.
+Historically, we've not been explicit about what the use cases are, and how
+they should be served. This SEED will fill this gap.
+
+--------
+Proposal
+--------
+
+Repositories
+============
+Pigweed will maintain the following types of code sample repositories:
+
+* **Quickstart**: `minimal, complete, reproducible
+ <https://stackoverflow.com/help/minimal-reproducible-example>`_ projects you
+ can clone to understand the basics of Pigweed and start a new `greenfield
+ project <https://en.wikipedia.org/wiki/Greenfield_project>`_. There will be
+ one Quickstart repository for each build system that Pigweed supports.
+* **Examples**: granular, comprehensive code examples of every Pigweed
+ module's API. The Examples repository can also demonstrate core use cases
+ that require using multiple modules together. There will only be one Examples
+ repository.
+* **Showcase**: Showstopper examples that demonstrate how to use Pigweed
+ to implement complex real-world applications. There will be many Showcase
+ repositories, each demonstrating a different application. These repositories
+ should inspire users, show them how to implement complex integrations, and
+ convince them that Pigweed is the best way to develop embedded projects.
+
+Standard board
+==============
+The Quickstart and Examples repositories will eventually focus on a single
+:ref:`seed-0122-standard-board`. But selecting the standard board is out of the
+scope of this SEED.
+
+---------------
+Detailed design
+---------------
+
+.. _seed-0122-quickstart:
+
+Quickstart repository
+=====================
+* **User journeys** these repositories serve:
+
+ * "I want to clone a minimal repository to create my own project from
+ scratch."
+ * "I want to understand the smallest set of steps needed to add Pigweed as a
+ dependency of my own existing project."
+ * "I'm just getting started with Pigweed and want a tutorial that will
+ put *some* code on device".
+
+* **Repository contents**: One repository per build system that demonstrates
+ the minimal set of Pigweed features:
+
+ #. Bootstrapping (downloading required tools, third-party dependencies, etc).
+ #. Building the minimal, viable, complete (MVC) application for
+ :ref:`target-host` and for the :ref:`seed-0122-standard-board`.
+ #. Flashing the application to the board.
+ #. Communicating with the board via :ref:`module-pw_console`.
+
+ Determining the exact content of the MVC app is out-of-scope for this SEED.
+ This is the subject of `SEED-0106
+ <https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/155430>`_.
+ However, every Quickstart repository will implement the same set of MVC
+ features.
+
+ There will be tutorial documentation associated with each of these
+ repositories, but it will be hosted in pigweed.git. Documentation generation
+ with :ref:`module-pw_docgen` falls outside the scope of Quickstart.
+
+ We may also add separate Quickstart repositories for boards other than the
+ "standard board".
+
+* **Locations**:
+
+ * https://pigweed.googlesource.com/pigweed/quickstart/bazel.git
+ * https://pigweed.googlesource.com/pigweed/quickstart/gn.git
+ * (No CMake quickstart. We offer support for integrating Pigweed into an
+ existing CMake project, but don't recommend CMake for a greenfield Pigweed
+ project and so have no quickstart repository for it.)
+
+.. _seed-0122-examples:
+
+Examples repository
+===================
+* **User journeys** this repository serves:
+
+ * "I want to see an example of how a module's API is used in the context of a
+ full, building project."
+ * "I want to use tokenized logging, how do I hook this up?"
+ * "I read you can customize the :ref:`module-pw_console`, can I see an example?"
+ * "I want to see how to configure a backend of this module."
+ * "How do I use method X from Pigweed module Y?"
+ * "How do I use Pigweed modules A and B together?"
+
+* **Repository contents**: One repository that contains a bunch of directories.
+ Each directory is meant to be consulted in isolation. Common use cases such
+ as logging over UART or blinking an LED, may get their own directories.
+ Related examples (e.g., examples for an individual module) may be grouped
+ into a directory hierarchy for clarity.
+
+ The individual examples may define their own build targets, but they are not
+ expected to set up independent builds. They're all part of one top-level build.
+
+ In general, it should be possible to build the examples using all of
+ Pigweed's supported build systems (Bazel, CMake, GN). However, if the
+ functionality being exemplified is only supported in some build systems (e.g.
+ :ref:`module-pw_docgen` is only supported in GN as of this writing), then its
+ examples can be restricted to those build systems.
+
+ Unlike Quickstart, this repository is a reference work: the user is not
+ expected to read through it "from beginning to end". Rather, they will come
+ here to view a specific example. We eventually expect to have hundreds or
+ even thousands of examples.
+
+ The documentation for the Examples repo will be hosted at http://pigweed.dev,
+ but will be built from source within the ``examples.git`` repo. Building
+ documentation using :ref:`module-pw_docgen` is one of the things we're
+ exemplifying.
+
+* **Location**: https://pigweed.googlesource.com/pigweed/examples.git
+
+Showcase repositories
+=====================
+* **User journeys** these repositories serve:
+
+ * "I want to see a cool project built using Pigweed."
+ * "I'm looking for a full-fledged demo of what Pigweed is capable of."
+ * "I'm looking for a Show HN submission."
+ * "I want to convince my team Pigweed is powerful enough for our use case."
+ * "I need proof that Pigweed is a better way to develop embedded projects."
+ * "I need proof that Pigweed is production-ready."
+
+* **Repository contents**: One repository per showcase project. These projects
+ are standalone, with documentation that explains what they do. They're not
+ necessarily easy to stand up yourself, and may require custom hardware that's
+ hard to source. :ref:`Kudzu <docs-blog-01-kudzu>` and `Gonk
+ <https://pigweed.googlesource.com/gonk.git>`_ are examples of showcase
+ projects.
+
+* **Locations**: Showcase projects can be hosted anywhere. Open-source projects
+ created by third parties and not hosted on https://pigweed.googlesource.com
+ can also be showcases.
+
+ We will host a list of Showcase projects, with brief descriptions, at
+ https://pigweed.dev/showcase.
+
+.. _seed-0122-standard-board:
+
+Standard board
+==============
+Pigweed will select a "standard board" for use in our code samples. Today, the
+de facto standard board is the STM32F429I-DISC1, but we expect to select a
+different standard board in the near future. Standard board selection will be
+discussed in a separate followup SEED.
+
+----
+FAQs
+----
+
+.. _seed-0122-existing-samples:
+
+How do existing code samples map to this scheme?
+================================================
+* `example/echo <https://pigweed.googlesource.com/pigweed/example/echo.git>`_
+ will be renamed to become :ref:`seed-0122-quickstart` for Bazel.
+* `sample_project
+ <https://pigweed.googlesource.com/pigweed/sample_project.git>`_ will be
+ renamed and reorganized to become the :ref:`seed-0122-examples`.
+* `Kudzu <https://pigweed.googlesource.com/pigweed/kudzu.git>`_ and `Gonk
+ <https://pigweed.googlesource.com/gonk.git>`_ are Showcase projects.
+
+
+What about inline code samples in the documentation?
+====================================================
+We will continue to provide inline code samples in the documentation, and later
+in 2024 may prototype solutions for ensuring they compile and pass assertions.
+But this is out of scope for this SEED.
+
+--------------
+Open questions
+--------------
+A followup SEED will discuss the selection of the "standard board" for Pigweed
+Quickstart and Examples repositories.
+
+The exact feature set of the MVC application demonstrated by the Quickstart
+repos is the subject of `SEED-0106
+<https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/155430>`_.
diff --git a/seed/BUILD.gn b/seed/BUILD.gn
index 62aa25808..810ed04b3 100644
--- a/seed/BUILD.gn
+++ b/seed/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2022 The Pigweed Authors
+# 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
@@ -14,76 +14,254 @@
import("//build_overrides/pigweed.gni")
-import("$dir_pw_docgen/docs.gni")
+import("seed.gni")
-pw_doc_group("docs") {
- sources = [ "0000-index.rst" ]
- group_deps = [
- ":0001",
- ":0002",
- ":0101",
- ":0102",
- ":0104",
- ":0105",
- ":0107",
- ":0108",
- ":0109",
- ":0110",
- ":0111",
- ":0112",
- ":0113",
- ]
-}
-
-pw_doc_group("0001") {
+pw_seed("0001") {
sources = [ "0001-the-seed-process.rst" ]
inputs = [ "0001-the-seed-process/seed-index-gerrit.png" ]
+ title = "The SEED Process"
+ status = "Meta"
+ author = "The Pigweed Authors"
+ facilitator = "N/A"
}
-pw_doc_group("0002") {
+pw_seed("0002") {
sources = [ "0002-template.rst" ]
+ title = "SEED Template"
+ status = "Meta"
+ author = "The Pigweed Authors"
+ facilitator = "N/A"
}
-pw_doc_group("0101") {
+pw_seed("0101") {
sources = [ "0101-pigweed.json.rst" ]
+ title = "pigweed.json"
+ status = "Accepted"
+ author = "Rob Mohr"
+ facilitator = "Ted Pudlik"
}
-pw_doc_group("0102") {
+pw_seed("0102") {
sources = [ "0102-module-docs.rst" ]
+ title = "Consistent Module Documentation"
+ status = "Accepted"
+ author = "Chad Norvell"
+ facilitator = "Kayce Basques"
}
-pw_doc_group("0104") {
+pw_seed("0103") {
+ changelist = 133971
+ title = "pw_protobuf: Past, present, and future"
+ status = "On Hold"
+ author = "Alexei Frolov"
+ facilitator = "Armando Montanez"
+}
+
+pw_seed("0104") {
sources = [ "0104-display-support.rst" ]
+ title = "Display Support"
+ status = "Accepted"
+ author = "Chris Mumford"
+ facilitator = "Anthony DiGirolamo"
}
-pw_doc_group("0105") {
+pw_seed("0105") {
sources = [ "0105-pw_tokenizer-pw_log-nested-tokens.rst" ]
+ title = "Nested Tokens and Tokenized Log Arguments"
+ status = "Accepted"
+ author = "Gwyneth Chen"
+ facilitator = "Wyatt Hepler"
+}
+
+pw_seed("0106") {
+ changelist = 155430
+ title = "Project Template"
+ status = "On Hold"
+ author = "Armando Montanez"
+ facilitator = "Kayce Basques"
}
-pw_doc_group("0107") {
+pw_seed("0107") {
sources = [ "0107-communications.rst" ]
+ title = "Pigweed Communications"
+ status = "Accepted"
+ author = "Wyatt Hepler"
+ facilitator = "Carlos Chinchilla"
}
-pw_doc_group("0108") {
+pw_seed("0108") {
sources = [ "0108-pw_emu-emulators-frontend.rst" ]
+ title = "Emulators Frontend"
+ status = "Accepted"
+ author = "Octavian Purdila"
+ facilitator = "Armando Montanez"
}
-pw_doc_group("0109") {
+pw_seed("0109") {
sources = [ "0109-comms-buffers.rst" ]
+ title = "Communication Buffers"
+ status = "Accepted"
+ author = "Taylor Cramer"
+ facilitator = "Erik Gilling"
}
-pw_doc_group("0110") {
+pw_seed("0110") {
sources = [ "0110-memory-allocation-interfaces.rst" ]
+ title = "Memory Allocation Interfaces"
+ status = "Accepted"
+ author = "Alexei Frolov"
+ facilitator = "Taylor Cramer"
}
-pw_doc_group("0111") {
+pw_seed("0111") {
sources = [ "0111-build-systems.rst" ]
+ title = "Make Bazel Pigweed's Primary Build System"
+ status = "Accepted"
+ author = "Ted Pudlik"
+ facilitator = "Armando Montanez"
}
-pw_doc_group("0112") {
+pw_seed("0112") {
sources = [ "0112-async-poll.rst" ]
+ title = "Async Poll Model"
+ status = "Accepted"
+ author = "Taylor Cramer"
+ facilitator = "Wyatt Hepler"
}
-pw_doc_group("0113") {
+pw_seed("0113") {
sources = [ "0113-bazel-cc-toolchain-api.rst" ]
+ title = "Add modular Bazel C/C++ toolchain API"
+ status = "Accepted"
+ author = "Armando Montanez"
+ facilitator = "Ted Pudlik"
+}
+
+pw_seed("0114") {
+ sources = [ "0114-channels.rst" ]
+ title = "Channels"
+ status = "Accepted"
+ author = "Wyatt Hepler"
+ facilitator = "Carlos Chinchilla"
+}
+
+pw_seed("0115") {
+ changelist = 176760
+ title = "pw_sensor: Sensors"
+ status = "Rejected"
+ author = "Yuval Peress"
+ facilitator = "Taylor Cramer"
+}
+
+pw_seed("0116") {
+ changelist = 177696
+ title = "pw_net Sockets"
+ status = "Open for Comments"
+ author = "Wyatt Hepler"
+ facilitator = "Taylor Cramer"
+}
+
+pw_seed("0117") {
+ changelist = 178350
+ title = "pw_i3c"
+ status = "Open for Comments"
+ author = "Jack Chen"
+}
+
+pw_seed("0118") {
+ changelist = 181836
+ title = "Sensor Read API"
+ status = "Draft"
+ author = "Taylor Cramer"
+}
+
+pw_seed("0119") {
+ sources = [ "0119-pw-sensor.rst" ]
+ title = "pw_sensor A sensor framework"
+ status = "Accepted"
+ inputs = [
+ "0119-pw-sensor/high-level-view.svg",
+ "0119-pw-sensor/data-pipeline.svg",
+ ]
+ author = "Yuval Peress"
+}
+
+pw_seed("0120") {
+ changelist = 182805
+ title = "pw_sensor Sensor driver configuration"
+ status = "Draft"
+ author = "Yuval Peress"
+}
+
+pw_seed("0121") {
+ changelist = 184224
+ title = "Pigweed Project Server"
+ status = "Draft"
+ author = "Chad Norvell"
+}
+
+pw_seed("0122") {
+ sources = [ "0122-code-samples.rst" ]
+ title = "Organize Pigweed code samples"
+ status = "Accepted"
+ author = "Ted Pudlik"
+ facilitator = "Kayce Basques"
+}
+
+pw_seed("0123") {
+ changelist = 188141
+ title = "Sprout Bazel C++ toolchain API into a separate repository"
+ status = "Draft"
+ author = "Ted Pudlik"
+ facilitator = "Armando Montanez"
+}
+
+pw_seed("0124") {
+ changelist = 188670
+ title = "Interfaces for Retrieving Size Information from Multisink"
+ status = "Draft"
+ author = "Jiacheng Lu"
+ facilitator = "Carlos Chinchilla"
+}
+
+pw_seed("0125") {
+ changelist = 192090
+ title = "Statistics Database"
+ status = "Draft"
+ author = "Erik Staats"
+}
+
+# This must be defined after all `pw_seed` targets, as it relies on information
+# exposed by them.
+pw_seed_index("seeds") {
+ index_file = "0000-index.rst"
+ seeds = [
+ ":0001",
+ ":0002",
+ ":0101",
+ ":0102",
+ ":0103",
+ ":0104",
+ ":0105",
+ ":0106",
+ ":0107",
+ ":0108",
+ ":0109",
+ ":0110",
+ ":0111",
+ ":0112",
+ ":0113",
+ ":0114",
+ ":0115",
+ ":0116",
+ ":0117",
+ ":0118",
+ ":0119",
+ ":0120",
+ ":0121",
+ ":0122",
+ ":0123",
+ ":0124",
+ ":0125",
+ ]
}
diff --git a/seed/seed.gni b/seed/seed.gni
new file mode 100644
index 000000000..66582c670
--- /dev/null
+++ b/seed/seed.gni
@@ -0,0 +1,139 @@
+# 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.
+
+import("//build_overrides/pigweed.gni")
+
+import("$dir_pw_build/python.gni")
+import("$dir_pw_docgen/docs.gni")
+
+# Defines a directory of SEED proposals, generating an RST snippet containing
+# information about each of them.
+#
+# Args:
+# index_file: Base .rst file in which the index will be defined.
+# seeds: Nonempty list of `pw_seed` targets defining the SEEDs to include in
+# the index. All targets must previously have been defined in the same
+# BUILD.gn file.
+#
+template("pw_seed_index") {
+ assert(defined(invoker.index_file), "Must provide an index file")
+ assert(defined(invoker.seeds) && invoker.seeds != [],
+ "A SEED index must contain SEEDs")
+
+ _gen_target = "${target_name}.gen"
+ _index_rst_output = "$target_gen_dir/${target_name}"
+
+ _script_args = [
+ "--output",
+ rebase_path(_index_rst_output, root_build_dir),
+ ]
+
+ foreach(_seed_target, invoker.seeds) {
+ _outputs = []
+ _outputs = get_target_outputs("${_seed_target}.metadata")
+ _script_args += [ rebase_path(_outputs[0], root_build_dir) ]
+ }
+
+ pw_python_action(_gen_target) {
+ script = "$dir_pw_docgen/py/pw_docgen/seed.py"
+ args = _script_args
+ outputs = [ _index_rst_output ]
+ deps = invoker.seeds
+ }
+
+ pw_doc_group(target_name) {
+ sources = [ invoker.index_file ]
+ inputs = [ _index_rst_output ]
+ group_deps = invoker.seeds
+ other_deps = [ ":$_gen_target" ]
+ }
+}
+
+# Defines a SEED document suitable for inclusion in a SEED directory.
+# The `target_name` of the SEED target should be its 4-digit number and nothing
+# else.
+#
+# Args:
+#
+# sources (optional): If the SEED docs are already in-tree, list of the RST
+# source files.
+#
+# inputs (optional): If the SEED docs are already in-tree, list of any
+# additional resource files the docs require (images, graphs, etc.).
+#
+# changelist (optional): If the SEED has not yet been merged, the number of the
+# CL on Gerrit where the SEED is being reviewed.
+#
+# title (required): The title of the SEED.
+#
+# authors (required): Comma-separated list of SEED authors.
+#
+# facilitator (optional): Pigweed team member facilitating the SEED.
+#
+# status (required): Status of the SEED. One of:
+# Draft, Open for Comments, Last Call, Accepted, Rejected, On Hold,
+# Deprecated, Superseded, Meta
+#
+# A SEED target must set either `sources` or `changelist` to be valid.
+template("pw_seed") {
+ _has_sources = defined(invoker.sources) && invoker.sources != []
+ assert(_has_sources || defined(invoker.changelist),
+ "A SEED must either have in-tree sources or an active CL")
+ assert(defined(invoker.title), "SEEDs must have a title")
+ assert(defined(invoker.status), "SEEDs must list their status")
+ assert(defined(invoker.author), "SEEDs must list their author(s)")
+
+ _metadata_file = "${target_gen_dir}/${target_name}.metadata.json"
+ _metadata_target = "${target_name}.metadata"
+
+ _metadata = {
+ number = target_name
+ title = invoker.title
+ status = invoker.status
+ author = invoker.author
+
+ if (defined(invoker.facilitator)) {
+ facilitator = invoker.facilitator
+ }
+ }
+
+ if (_has_sources) {
+ _sources = invoker.sources
+ _metadata.rst_file = _sources[0]
+ } else {
+ _metadata.changelist = invoker.changelist
+ }
+
+ generated_file(_metadata_target) {
+ contents = _metadata
+ output_conversion = "json"
+ outputs = [ _metadata_file ]
+ }
+
+ if (_has_sources) {
+ pw_doc_group(target_name) {
+ other_deps = [ ":${_metadata_target}" ]
+ forward_variables_from(invoker,
+ [
+ "sources",
+ "inputs",
+ ])
+ }
+ } else {
+ group(target_name) {
+ deps = [ ":${_metadata_target}" ]
+ not_needed(invoker, [ "*" ])
+ }
+ }
+}