From 9425826203e1c954491a6a29ae84daf1a5edda2c Mon Sep 17 00:00:00 2001
From: Loek Le Blansch <loek@pipeframe.xyz>
Date: Thu, 20 Jun 2024 17:53:58 +0200
Subject: more documentation (WIP design.adoc)

---
 docs/design.adoc | 96 +++++++++++++++++++++++++++++++-------------------------
 1 file changed, 53 insertions(+), 43 deletions(-)

(limited to 'docs/design.adoc')

diff --git a/docs/design.adoc b/docs/design.adoc
index 5ebbb15..e54c970 100644
--- a/docs/design.adoc
+++ b/docs/design.adoc
@@ -117,7 +117,7 @@ the following:
 ** Aggregating game state for all installed puzzle modules.
 ** Reading and writing game state for all installed puzzle modules.
 ** Broadcasting updates internally.
-* Serve TCP socket connections for—
+* Serve a TCP socket for—
 ** Sending state updates
 ** Manually updating game state
 ** Integration with the bomb
@@ -146,6 +146,7 @@ The criteria for the main controller are:
 The requirements document compares various microcontrollers that fit these
 criteria. After this comparison, the decision was made to utilize the Raspberry
 Pi Pico W as main controller during development.
+// TODO: this was a bad choice
 
 [[fig:main-controller-top]]
 .Main controller top-level block diagram
@@ -165,9 +166,22 @@ peripherals is handled through a central I^2^C bus referred to as the 'puzzle
 bus'. This design was again carried over from the hardware design from the
 21-22 group cite:[2122_design].
 
-The only notable difference made this year was the removal of the
-"HarwareInterrupt" line1{empty}footnote:[This is not a typo], which was
-connected but not utilized cite:[research].
+The previously specified "HarwareInterrupt" line1{empty}footnote:[This is not a
+typo] has been removed this year, as it was connected but not utilized
+cite:[research].
+
+To optimize for flexibility and extensibility, the puzzle bus should ideally
+function as a network (similar to the CAN bus), to allow puzzle modules to send
+responses asynchronously. I^2^C was initially chosen for the puzzle bus due to
+its widespread availability on microcontrollers and in peripherals, but does
+not provide any network-like capabilities.
+
+To archive network-like capabilities, the puzzle bus is specified to be a
+multi-master I^2^C bus, and all puzzle modules are specified to be I^2^C
+multi-master controllers that are slave-addressible. The multi-master part is
+required to prevent I^2^C transmissions from being corrupted in the event of a
+bus collision, and the slave-addressible part is required to both send and
+receive messages on the same controller.
 
 Address definitions and protocol specifications are further detailed in
 <<sec:lv2-bus>>.
@@ -202,15 +216,15 @@ image::img/system-bus.svg[]
 [[sec:lv2]]
 == Modules
 
-This section elaborates on the top-level specifications from <<sec:lv1>> with
-additional hardware specifications and software design decisions.
+This section elaborates on the top-level (hardware) specifications from
+<<sec:lv1>> with software design decisions.
 
 === Puzzle Module Framework
 
 This subsection defines aspects of the 'puzzle framework' and the interface
 that allows puzzle modules to integrate with this framework. All communication
 described within this subsection refers to 'internal' communication between the
-main controller and puzzle module.
+main controller and puzzle modules on the puzzle bus.
 
 The puzzle framework is the foundation of the puzzle box software, and is
 designed to facilitate the following:
@@ -226,56 +240,52 @@ designed to facilitate the following:
 ==== State
 
 All puzzle modules implement the same state machine shown in
-<<fig:puzzle-module-common-state>>. Note that the arrows indicate state
-transitions that a puzzle module may take on its own. The main controller also
-allows the game operator to manually set the current state as one of the states
-on the right half of <<fig:puzzle-module-common-state>>, which can be used to
-skip a puzzle if a player is stuck (<<reqs.adoc#req:edge-skip-puzzle>>) or
-reset a game if it is malfunctioning (<<reqs.adoc#req:edge-manual-reset>>).
-
-Puzzle modules start in the 'uninitialized' state, where they repeatedly send
-messages to the main controller (see <<sec:main-bridge>>). The state transition
-from 'uninitialized' to 'reset' is forced by the main controller upon
-initialization. States on the right half of <<fig:puzzle-module-common-state>>
-are used during gameplay.
+<<fig:puzzle-module-common-state>>. Note that solid arrows indicate state
+transitions that a puzzle module may take on its own, while dashed arrows
+indicate state transitions forced by the main controller. The main controller
+also allows the game operator to manually set the current state as one of the
+states on the right half of <<fig:puzzle-module-common-state>>, which can be
+used to skip a puzzle if a player is stuck (<<reqs.adoc#req:edge-skip-puzzle>>)
+or reset a game if it is malfunctioning (<<reqs.adoc#req:edge-manual-reset>>).
+
+Puzzle modules start in the 'uninitialized' state, where they wait until the
+main controller sends a SET STATE command. Receiving this command indicates to
+the puzzle module that it was successfully registered by the main controller,
+and that it may transition from the 'uninitialized' state to the 'reset' state.
 
 [[fig:puzzle-module-common-state]]
 .Global puzzle module state machine
 image::img/puzzle-module-common-state.svg[]
 
 The state machine described in <<fig:puzzle-module-common-state>> is referred
-to as the global state. Puzzle modules may also declare and define custom state
-variables, which is referred to as auxiliary state. These auxiliary state
-variables contain game-specific variables; e.g. the binary state of each button
-on the Neotrellis puzzle module, or the last passcode entered on the vault
-puzzle module.
+to as the global state. Puzzle modules may also declare and define custom
+variables, which are referred to as properties. These properties may contain
+game-specific variables; e.g. the binary state of each button on the Neotrellis
+puzzle module, or the last passcode entered on the vault puzzle module.
 
-Separating the auxiliary state from the generic state allows the main
-controller to handle the auxiliary state as an arbitrary blob, which allows for
-future expansion without modification of the main controller software.
+Separating properties from the global state allows the main controller to
+handle these property values as an arbitrary blob, which allows for future
+expansion without modification of the main controller software.
 
 ==== Commands
 
-The puzzle module framework describes the following commands:
+The puzzle module framework describes the following command *types*:
+
+* ``PROP``: property
+* ``MAGIC``: handshake
+* ``STATE``: global state
 
-* Read state
-* Write state
-* Update
+Each command also has a specific *action*:
 
-The 'read' and 'write' commands are used to communicate both types of state
-defined in <<sec:framework-state>>.
+* ``REQ``: request
+* ``RES``: response
+* ``SET``: (over)write
 
-To avoid issues caused by state synchronization memory consumption on the main
-controller and puzzle modules, auxiliary state is only stored on each
-respective puzzle module's controller. Only global state is cached on the main
-controller to reduce the number of back-and-forth messages required for state
-updates.
+Not all commands define behavior for all actions (e.g. there is no MAGIC SET
+command).
 
-These commands are sufficient to realize the puzzle box, but this means that
-the puzzle box would rely heavily on polling-based updates internally. To solve
-this, the 'update' command was created. This command is utilized for various
-kinds of updates, including registering new puzzle modules and updating global
-state.
+The Doxygen-generated pages for these command types explain their usage, and
+will not be repeated here.
 
 === Main Controller
 
-- 
cgit v1.2.3


From 67f076b151d35a36800734cb31a403fac92ffb6d Mon Sep 17 00:00:00 2001
From: Loek Le Blansch <loek@pipeframe.xyz>
Date: Fri, 21 Jun 2024 13:22:18 +0200
Subject: WIP more design document + add TODOs

---
 docs/design.adoc                          | 332 +++++++++++++++++-------------
 docs/handover.adoc                        |   3 +-
 docs/img/.gitignore                       |   2 +
 docs/img/sequence-puzzle-module-init.puml |  17 ++
 docs/img/sequence-puzzle-module-init.svg  |   3 -
 docs/img/style.ipuml                      |   1 +
 docs/makefile                             |   1 +
 lib/pbdrv/pb.h                            |  19 +-
 8 files changed, 222 insertions(+), 156 deletions(-)
 create mode 100644 docs/img/sequence-puzzle-module-init.puml
 delete mode 100644 docs/img/sequence-puzzle-module-init.svg

(limited to 'docs/design.adoc')

diff --git a/docs/design.adoc b/docs/design.adoc
index e54c970..7d9759a 100644
--- a/docs/design.adoc
+++ b/docs/design.adoc
@@ -219,12 +219,36 @@ image::img/system-bus.svg[]
 This section elaborates on the top-level (hardware) specifications from
 <<sec:lv1>> with software design decisions.
 
-=== Puzzle Module Framework
+=== Software module separation
 
-This subsection defines aspects of the 'puzzle framework' and the interface
-that allows puzzle modules to integrate with this framework. All communication
-described within this subsection refers to 'internal' communication between the
-main controller and puzzle modules on the puzzle bus.
+[[fig:software-component]]
+.Software library components
+image::img/software-components.svg[]
+
+<<fig:software-component>> shows a software component diagram with an example
+Arduino-based puzzle module, the main controller and the puzzle box client.
+Notable properties of this architecture include:
+
+* The Arduino SDK, FreeRTOS, mpack, and RPI Pico SDK are external libraries,
+	and with the exception of mpack, these have not been modified.
+* The puzzle bus driver is split into a (portable) standalone library and a
+	module-specific driver.
+* There is a separate library for (de)serializing I^2^C commands for
+	transmission over TCP.
+
+The specific decision to split the puzzle bus driver and create a separate
+I^2^C over TCP library was made to avoid writing a command set separate from
+internal puzzle bus commands (i.e. one specific to TCP connections). This
+architecture allows the puzzle box client to not only control the main
+controller, but also directly inspect puzzle bus messages for debugging and
+development of future puzzle modules (<<reqs.adoc#req:main-static>>).
+
+=== Puzzle module framework
+
+This subsection defines aspects of the 'puzzle framework': the interface that
+allows puzzle modules to integrate with the puzzle bus main controller. All
+communication described within this subsection refers to 'internal'
+communication between the main controller and puzzle modules on the puzzle bus.
 
 The puzzle framework is the foundation of the puzzle box software, and is
 designed to facilitate the following:
@@ -240,18 +264,18 @@ designed to facilitate the following:
 ==== State
 
 All puzzle modules implement the same state machine shown in
-<<fig:puzzle-module-common-state>>. Note that solid arrows indicate state
+<<fig:puzzle-module-common-state>>. Note that continuous arrows indicate state
 transitions that a puzzle module may take on its own, while dashed arrows
 indicate state transitions forced by the main controller. The main controller
-also allows the game operator to manually set the current state as one of the
-states on the right half of <<fig:puzzle-module-common-state>>, which can be
-used to skip a puzzle if a player is stuck (<<reqs.adoc#req:edge-skip-puzzle>>)
-or reset a game if it is malfunctioning (<<reqs.adoc#req:edge-manual-reset>>).
+also allows the game operator to manually set a module''s global state to one of
+these states, which can be used to skip a puzzle if a player is stuck
+(<<reqs.adoc#req:edge-skip-puzzle>>) or reset a game if it is malfunctioning
+(<<reqs.adoc#req:edge-manual-reset>>).
 
 Puzzle modules start in the 'uninitialized' state, where they wait until the
 main controller sends a SET STATE command. Receiving this command indicates to
 the puzzle module that it was successfully registered by the main controller,
-and that it may transition from the 'uninitialized' state to the 'reset' state.
+and that it may transition from the 'uninitialized' state to the 'idle' state.
 
 [[fig:puzzle-module-common-state]]
 .Global puzzle module state machine
@@ -269,70 +293,124 @@ expansion without modification of the main controller software.
 
 ==== Commands
 
-The puzzle module framework describes the following command *types*:
+// TODO: cleanup
+
+All messages sent over the puzzle bus have a similar format. This format is
+shown in Table 2. Notable details include:
+
+The 'subject' field does not have to match the I^2^C address of the message
+sender or recipient
+
+Property 0x00 stores a module's global state
+
+.Puzzle bus message format
+[%autowidth]
+|===
+| Field | Content
+
+| Command | Enum: read, write, update
+| Subject | I^2^C address (7-bit)
+| Property | Address (8-bit)
+| Value | Byte string (variable length)
+|===
+
+The messages described in Table 2 are (de)serialized using Google's protocol
+buffer library. This choice was made after considering various alternative
+options for sending structured messages cite:[research].
+
+<<fig:sequence-puzzle-module-init>> shows an example of how messages are
+exchanged for the initialization of a puzzle module.
+
+<<fig:sequence-puzzle-finish>> shows an example exchange where the last puzzle
+module (A) is solved while (B) is already solved.
+
+. First, module A sets it's own state to 'solved' and subsequently informs the
+  main controller of this change.
+. As a result of this update notification, the main controller queries puzzle
+  module A for its new global state.
+. Once the main controller has received and confirmed that all puzzle module
+  global states are set to 'solved', the main controller sets its own state to
+  'solved', and broadcasts an update message to all puzzle modules.
+. As a result of the update message from the main controller, module B requests
+  the main controller's new global state, and is able to verify that all puzzle
+  modules have been solved.
+
+In this example, module B could be the vault puzzle module, which displays a
+code when the entire puzzle box is solved.
+
+[[fig:sequence-puzzle-finish]]
+.Puzzle box finish sequence diagram
+image::img/sequence-puzzle-finish.svg[]
+
+The puzzle module framework describes the following command _types_:
 
 * ``PROP``: property
 * ``MAGIC``: handshake
 * ``STATE``: global state
 
-Each command also has a specific *action*:
+Each command also has a specific _action_:
 
 * ``REQ``: request
 * ``RES``: response
 * ``SET``: (over)write
 
-Not all commands define behavior for all actions (e.g. there is no MAGIC SET
-command).
+- Not all commands define behavior for all actions (e.g. there is no MAGIC SET
+	command).
+- A REQ command is always answered by a RES command.
+- A SET command does not have a reply.
+- All commands are sent as I^2^C writes.
 
 The Doxygen-generated pages for these command types explain their usage, and
-will not be repeated here.
+will not be restated in this document.
 
 === Main Controller
 
 This subsection defines the function and state of the main controller.
 
+==== Initializing puzzle modules
+
+The main controller sends a MAGIC REQ command to every I^2^C address on
+startup. The MAGIC command effectively serves as a 'secret handshake' (using a
+_magic_ value) which is used to distinguish between puzzle modules and
+unrelated I^2^C devices. Puzzle modules start in the 'uninitialized' state (see
+<<fig:puzzle-module-common-state>>), in which they do nothing. Puzzle modules
+in this state are still able to reply to requests, including MAGIC REQ
+commands. When the main controller receives a MAGIC RES command, the I^2^C
+address of the sender is added to an internal list for puzzle modules.
+
+After the initial handshake request 'wave' (bus scan), all puzzle modules are
+repeatedly asked for their global state using a STATE REQ command. This request
+also includes the global state of the requesting puzzle module, which is always
+the main controller (under normal circumstances). Upon receiving the first
+STATE REQ command, a puzzle module knows it has been registered successfully by
+the main controller, and may transition into the 'idle' state.
+
+[[fig:sequence-puzzle-module-init]]
+.Puzzle module initialization sequence diagram
+image::img/sequence-puzzle-module-init.svg[]
+
+(Activated lifeline indicates the module is no longer in 'uninitialized' state)
+
 ==== State
 
-The global state of the main controller is an aggregated version of all
-installed puzzle modules and is defined by the state machine shown in
+The global state of the main controller is an aggregation of all installed
+puzzle modules and is defined by the state machine shown in
 <<fig:main-controller-state>>.
 
 [[fig:main-controller-state]]
 .Main controller global state machine
 image::img/main-controller-state.svg[]
 
-The following list describes when each state is active:
+The main controller global state is determined using the following rules:
 
-* If all puzzle modules are in the 'reset' state, the main controller is also
-  in the 'reset' state.
+* If all puzzle modules are in the 'idle' state, the main controller is also in
+	the 'idle' state.
 * If all puzzle modules are in the 'solved' state, the main controller is also
-  in the 'solved' state.
+	in the 'solved' state.
 * Else, the main controller is in the 'playing' state.
 
-Because the main controller's state is only dependent on the installed puzzle
-modules' state, it is only updated when a puzzle module sends an update
-notification. When the global state of the main module changes, an update
-broadcast is sent to all puzzle modules.
-
-To simplify the commands used to control the puzzle box, the list of installed
-puzzle modules is stored as an auxiliary state variable of the main controller.
-
-==== Initializing Puzzle Modules
-
-Puzzle modules start in the 'uninitialized' state (see
-<<fig:puzzle-module-common-state>>). In this state, the puzzle module
-repeatedly sends an update command to the main controller. The main controller
-responds to this message by sending a 'set state' command with the target state
-as 'reset' as reply. Before this response is sent, the main controller
-internally adds the bus address of the puzzle module requesting to be
-initialized to the list of installed puzzle modules. From the main controller's
-point of view, this reply marks the moment the initialization is complete.
-
-[[fig:sequence-puzzle-module-init]]
-.Puzzle module initialization sequence diagram
-image::img/sequence-puzzle-module-init.svg[]
-
-(Activated lifeline indicates the module is no longer in 'uninitialized' state)
+Due to the repeated STATE REQ commands, this effectively informs the puzzle
+modules when the puzzle box is completely solved.
 
 [[sec:main-bridge]]
 ==== Bridge
@@ -343,99 +421,83 @@ The Raspberry Pi 3B+ used as main controller during the 21-22 run of the
 project set up a Wi-Fi Mesh network cite:[2122_design] to communicate with the
 puzzle box. This year's main controller (Raspberry Pi Pico W cite:[research])
 uses a standard 802.11b/g/n access point instead
-(<<reqs.adoc#req:main-802-11-ap>>).
+(<<reqs.adoc#req:main-802-11-ap>>) as it is a simpler solution.
+
+On this network, the main controller hosts a server that serves a TCP socket
+connection. This socket is used to directly forward all internal messages sent
+on the puzzle bus to the puzzle box client bidirectionally (on behalf of the
+main controller).
+
+Due to the separation of the puzzle bus driver code into a standalone library
+for reading/writing puzzle bus commands, and a puzzle module-specific code, the
+puzzle box client is able to read/write raw I^2^C commands directly. A separate
+library was made for serializing I^2^C messages so they can be sent over the
+TCP connection.
 
-On this network, the main controller hosts a server that serves TCP socket
-connections. These sockets directly forward all internal messages sent to the
-main controller bidirectionally (i.e. on behalf of the main controller).
 Detailed specifications on the TCP socket server are in
 <<sec:lv3-remote-control>>.
 
-==== Operating System
+==== Operating system
+
+TODO
 
-The research document cite:[research] contains a detailed comparison of various
-operating systems that are suitable to realize the functionality described in
-this section. After this comparison, the decision was made to utilize FreeRTOS
-as the operating system on the Rasberry Pi Pico W.
+- main controller does tcp and i2c at the same time
+- simple scheduler is needed
+- curriculum only has FreeRTOS and Zephyr
+- Zephyr is overkill
+- FreeRTOS it is
+
+- due to RP2040 limitations, delays are used
+- most SDKs I2C drivers directly call I2C message handlers from ISR
+- puzzle bus driver functions can no longer be called directly from ISR handlers due to the delay
+- FreeRTOS is also used in puzzle modules, though this can likely be removed in the future
 
 [[sec:lv2-bus]]
-=== Puzzle Bus
+=== Puzzle bus
 
 This section describes the addresses and communication protocol used on the
 puzzle bus. These specifications only apply to messages sent internally in the
 puzzle box, as messages forwarded by the bridge (see <<sec:main-bridge>>) are
 sent on behalf of the main controller.
 
-==== Addresses
-
-The I^2^C addresses remain mostly unchanged from the 20-21 group's
-implementation cite:[2021_design]. Addresses that were modified since the 20-21
-implementation are marked with an asterisk. Table 1 lists these addresses for
-reference. These addresses are also used to identify specific puzzle modules.
-
-.I^2^C address reference
-[%autowidth]
-|===
-| Peripheral | Address
-
-| Main controller | 0x10*
-| Neotrellis puzzle controller | 0x11*
-| Neotrellis button matrix | 0x12*
-| Software puzzle controller | 0x03
-| Hardware puzzle controller | 0x04
-| Vault puzzle controller | 0x06
-|===
-
-==== Messages
-
-All messages sent over the puzzle bus have a similar format. This format is
-shown in Table 2. Notable details include:
-
-The 'subject' field does not have to match the I^2^C address of the message
-sender or recipient
-
-Property 0x00 stores a module's global state
+==== Guidelines
 
-.Puzzle bus message format
-[%autowidth]
-|===
-| Field | Content
+The following assumptions are made about puzzle modules:
 
-| Command | Enum: read, write, update
-| Subject | I^2^C address (7-bit)
-| Property | Address (8-bit)
-| Value | Byte string (variable length)
-|===
+* Puzzle modules do not take initiative to send REQ or SET commands. They only
+	respond to requests from the main controller.
+* Puzzle modules can be distinguished from unrelated I^2^C peripherals using
+	the MAGIC command.
+* Puzzle modules are I^2^C multi-master controllers that are slave-addressable
+	in master mode.
+* The main controller is a puzzle module, but with the following differences:
+** The main controller is allowed to initiate REQ and SET commands.
+** The main controller's global state is an aggregation of all other puzzle
+	 modules, and ignores STATE SET commands.
 
-The messages described in Table 2 are (de)serialized using Google's protocol
-buffer library. This choice was made after considering various alternative
-options for sending structured messages cite:[research].
+These guidelines allow the following simplifications:
 
-<<fig:sequence-puzzle-module-init>> shows an example of how messages are
-exchanged for the initialization of a puzzle module.
+* Puzzle modules may assume they are always being addressed by the main
+	controller (this simplifies the message architecture).
+* The puzzle bus may be shared with regular I^2^C peripherals without causing
+	issues.
 
-<<fig:sequence-puzzle-finish>> shows an example exchange where the last puzzle
-module (A) is solved while (B) is already solved.
+==== Addresses
 
-. First, module A sets it's own state to 'solved' and subsequently informs the
-  main controller of this change.
-. As a result of this update notification, the main controller queries puzzle
-  module A for its new global state.
-. Once the main controller has received and confirmed that all puzzle module
-  global states are set to 'solved', the main controller sets its own state to
-  'solved', and broadcasts an update message to all puzzle modules.
-. As a result of the update message from the main controller, module B requests
-  the main controller's new global state, and is able to verify that all puzzle
-  modules have been solved.
+The RPI Pico SDK prohibits the use of I^2^C addresses reserved by the I^2^C
+specification. This means different addresses from previous years are used.
+These addresses are indexed in the code under a shared header (see
+``lib/pbdrv/pb.h``).
 
-In this example, module B could be the vault puzzle module, which displays a
-code when the entire puzzle box is solved.
+The same I^2^C address may be used by two different puzzle modules, but this
+will make it impossible for them to be used simultaniously.
 
-[[fig:sequence-puzzle-finish]]
-.Puzzle box finish sequence diagram
-image::img/sequence-puzzle-finish.svg[]
+The I^2^C addresses are also used to determine the puzzle sequence (i.e. the
+order in which puzzle modules are set to the 'playing' state). The sequence is
+determined by the main controller on startup, and consists of the connected
+puzzle modules' addresses in descending order (i.e. highest address first).
 
-=== NeoTrellis Puzzle
+=== NeoTrellis puzzle
 
 This subsection defines aspects of the 'NeoTrellis puzzle' module and gives a
 summary of how the puzzle is meant to be solved. This module will be created to
@@ -462,7 +524,7 @@ diagram has been shown in <<fig:neotrellis-io>>.
 .NeoTrellis puzzle in-out
 image::img/neotrellis-io.png[]
 
-=== Software Puzzle
+=== Software puzzle
 
 This subsection defines aspects of the 'software puzzle' module and gives a
 summary of how the puzzle is meant to be solved. This module will be created to
@@ -502,9 +564,9 @@ code. This is shown in <<fig:software-io>>.
 .Software puzzle in-out
 image::img/software-io.png[]
 
-=== Hardware Puzzle
+=== Hardware puzzle
 
-==== Hardware Puzzle gameplay
+==== Hardware puzzle gameplay
 
 The hardware puzzle has a logic gate puzzle engraved on the front plate of the
 puzzle box. To solve the puzzle, the user must set the toggle switches to the
@@ -522,7 +584,7 @@ The inputs and outputs of this puzzle have been taken from the design document
 of the previous group which worked on this project (21-22). This input and
 output diagram has been shown in Figure ??.
 
-=== Vault Puzzle
+=== Vault puzzle
 
 ==== Vault puzzle gameplay
 
@@ -539,35 +601,9 @@ clicked the vault resets and they need to start over from the beginning.
 .Vault puzzle in-out
 image::img/vault-io.png[]
 
-=== Bomb device
-
-==== Bomb device connection
-
-The bomb connects to a WiFi-network using the 802.11x standard. The hub hosts
-an interface that can be used to identify all the devices including the bomb
-and also pair it to a puzzlebox. After that the game can be set-up and a given
-countdown time and start time will be communicated to the bomb over a TCP
-socket connection. The hub generates a code that will be send to both the
-puzzlebox and bomb so that both devices know what would be or can be expected.
-
-The bomb can also use the WiFi connection to sync. the time.
-
-==== Device inputs & outputs
-
-[[fig:bomb-io]]
-.Bomb device in-out
-image::img/bomb-io.png[]
-
 == Components
 [[sec:lv3-remote-control]]
-=== Remote Control
-==== Socket Server
-==== Socket Commands
-=== Neotrellis Puzzle
-=== Game state diagrams, activity diagrams (if applicable)
-=== Software Puzzle
-=== Hardware Puzzle
-=== Vault Puzzle
+=== Remote control
 
 [appendix]
 == NeoTrellis puzzle example
diff --git a/docs/handover.adoc b/docs/handover.adoc
index 0e8af5a..6918256 100644
--- a/docs/handover.adoc
+++ b/docs/handover.adoc
@@ -109,7 +109,8 @@ Our project documentation was originally written in Microsoft Word, but we
 later transferred all documentation to AsciiDoc because of issues where
 OneDrive would roll back changes. If possible, use a documentation system or
 format that allows using an external version control system like Git to avoid
-losing content.
+losing content. This is also the reason why our documents may contain
+formatting/style errors.
 
 === Misconceptions
 
diff --git a/docs/img/.gitignore b/docs/img/.gitignore
index afafe8d..529fbaa 100644
--- a/docs/img/.gitignore
+++ b/docs/img/.gitignore
@@ -1 +1,3 @@
 software-components.svg
+sequence-puzzle-module-init.svg
+sequence-puzzle-finish.svg
diff --git a/docs/img/sequence-puzzle-module-init.puml b/docs/img/sequence-puzzle-module-init.puml
new file mode 100644
index 0000000..3d2fa56
--- /dev/null
+++ b/docs/img/sequence-puzzle-module-init.puml
@@ -0,0 +1,17 @@
+@startuml
+!include style.ipuml
+
+participant "main controller" as main
+participant "puzzle module" as mod
+
+activate main
+
+main -> mod : MAGIC REQ
+mod -> main : MAGIC RES
+
+|||
+
+main -> mod ++: STATE REQ
+mod -> main : STATE RES
+
+@enduml
diff --git a/docs/img/sequence-puzzle-module-init.svg b/docs/img/sequence-puzzle-module-init.svg
deleted file mode 100644
index 2e8db4f..0000000
--- a/docs/img/sequence-puzzle-module-init.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="217px" height="151px" viewBox="-0.5 -0.5 217 151"><defs/><g><rect x="20" y="0" width="40" height="20" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 40 20 L 40 150" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 10px; margin-left: 21px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Arial; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">Main</div></div></div></foreignObject><image x="21" y="3.5" width="38" height="17" xlink:href="data:image/png;base64,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"/></switch></g><rect x="35" y="50" width="10" height="100" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 139.5 70 L 120 70 L 51.37 70" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 46.12 70 L 53.12 66.5 L 51.37 70 L 53.12 73.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 70px; margin-left: 92px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Arial; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">update</div></div></div></foreignObject><image x="75" y="64" width="34" height="18.5" xlink:href="data:image/png;base64,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"/></switch></g><rect x="130" y="0" width="20" height="20" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 140 20 L 140 150" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 18px; height: 1px; padding-top: 10px; margin-left: 131px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Arial; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">A</div></div></div></foreignObject><image x="131" y="3.5" width="18" height="17" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABECAYAAAAiL3M8AAAAAXNSR0IArs4c6QAAA35JREFUeF7tmk3ITUEYx39vQpJENmxkYSHFjmKjUDa+SSgpiiKSUpQk5atQsqAo+Vz4tlGirBQlWUhWsmFhIcnCQsxT59U0Pfeec8+cmXkXz6l3896ZufP8zn/+859z7hB29SUwZHz6EzBANQoxQAYozkRMQaYgU1AcAVNQHL+R4EFTgWvAEq+UD8B69/c+rrz43iMB0BrgnlLKfuAc8De+zPYjlAY0FjgN7FFKeAZsAb62Ly++Z2lAs4E7wKyqFIEhS274Wgvcjy+z/QilAe0ALnpwjgOHPEhXgd3Ar/YlxvUsCWgScAVYXZXwAtgLnAKWVf8rbtYlAc0DHnpquQSIMe8Djnn3vahZlwI0yu1OR4DDHoidDpZAWgg8ASZUnxU161KApgE3gUWe/ywH3gBTgOveMpMmxcy6FKAw+9wFtrvl9QOQOckyO+Opq5hZlwA0rgqAsoMNX6HPhP4k2/+wwuK2pQF7lwCkZZ+w+InAZWBdabMuAUiWz1mvcPGbXW4H+xncXD8jyUdFzDo3oDD7SOHiPZKHwitUWhGzzg0o3MLfARuAjwqg8W5HuwBsLWnWOQFp2ec8cAD43cM7NwM3vM/ErFcBrwf02tbNcwKaDtwCFnizrcs3M4DbLjjOL2XWOQGF2eclsAn43Of2jgFOVrlouFlWs84FSPOTE9VR40+N/pc61T0N2tQpr/WSCjvmAhTuSLKlyyn+eYNKtEey2ZJ1LkBh9hlkmWjmns2scwDSsk8D4dQ2kUciR90yrVuitQP1a5AD0GLggff4ImrCXudBVNj6O1MD0pZH68kqHZObdWpAWo55685e31pQGu2UOBeYnDNZpwYUZp8Yc9VeEcWM1+gepQSkZZ9eJ/dGkwVWAI+CxknNOiWgOYA8KZzpFdTr5N4UkJaJ5G2InNm+NB1kkHapAGmPTfud3JvOWRtX+iYz61SAtOxTd3JvCklTZrJknQqQln1WAo+bUujTTvO2ZGadApBkHzHOgwlDnfaLkCRmnQKQln26nnz4Xk3uxSv3ZHIj8KkDlf4fIgWgHE8BeyX0zs26a0CaP8g5bJv7YcL3Lu8sEL47k+E7N+uuAXXMoPxwBqjmHhggAxS3TE1BpiBTUBwBU1AcP/MgU5ApKI6AKSiOn3mQKcgUFEfAFBTHzzzIFGQKiiNgCorjZx5kCjIFxREwBcXx+wf5lq5FzOjpHAAAAABJRU5ErkJggg=="/></switch></g><rect x="135" y="130" width="10" height="20" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 140.02 110 L 170 110 L 170 130 L 151.37 130" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 146.12 130 L 153.12 126.5 L 151.37 130 L 153.12 133.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 1px; height: 1px; padding-top: 120px; margin-left: 152px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: left;"><div style="display: inline-block; font-size: 11px; font-family: Arial; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">state := reset</div></div></div></foreignObject><image x="152" y="114" width="64" height="15.75" xlink:href="data:image/png;base64,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"/></switch></g><path d="M 45 90 L 90 90 L 133.13 90" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 138.38 90 L 131.38 93.5 L 133.13 90 L 131.38 86.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 90px; margin-left: 92px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Arial; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">state := reset</div></div></div></foreignObject><image x="60" y="84" width="64" height="15.75" xlink:href="data:image/png;base64,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"/></switch></g><path d="M 0 50 L 200 50" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-end; justify-content: unsafe flex-end; width: 1px; height: 1px; padding-top: 47px; margin-left: 198px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: right;"><div style="display: inline-block; font-size: 11px; font-family: Arial; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">power on</div></div></div></foreignObject><image x="153" y="34.5" width="45" height="15.75" xlink:href="data:image/png;base64,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"/></switch></g><path d="M 135 140 L 120 140 L 51.37 140" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 46.12 140 L 53.12 136.5 L 51.37 140 L 53.12 143.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 140px; margin-left: 90px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 11px; font-family: Arial; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">update</div></div></div></foreignObject><image x="73" y="132.625" width="34" height="18.5" xlink:href="data:image/png;base64,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"/></switch></g></g></svg>
\ No newline at end of file
diff --git a/docs/img/style.ipuml b/docs/img/style.ipuml
index 25bb6d7..9ea5170 100644
--- a/docs/img/style.ipuml
+++ b/docs/img/style.ipuml
@@ -1,3 +1,4 @@
 !theme plain
 skinparam RoundCorner 0
+hide footbox
 
diff --git a/docs/makefile b/docs/makefile
index 15ea3a4..d180398 100644
--- a/docs/makefile
+++ b/docs/makefile
@@ -24,4 +24,5 @@ ASCIIDOCTOR_ARGS += --backend pdf
 	plantuml -tsvg $<
 
 design.pdf: img/software-components.svg
+design.pdf: img/sequence-puzzle-module-init.svg
 
diff --git a/lib/pbdrv/pb.h b/lib/pbdrv/pb.h
index 0f2e9d1..e8037ae 100644
--- a/lib/pbdrv/pb.h
+++ b/lib/pbdrv/pb.h
@@ -1,23 +1,34 @@
 #pragma once
 
+//! I2C bus speed in hertz (100 KHz)
 #define PB_CLOCK_SPEED_HZ 100000
+//! I2C bus timeout delay in milliseconds
 #define PB_TIMEOUT_MS 10
+//! I2C bus timeout delay in microseconds
 #define PB_TIMEOUT_US (1e3 * PB_TIMEOUT_MS)
 
-// Adafruit NeoTrellis modules
+//! Adafruit NeoTrellis module 1 I2C address
 #define PB_ADDR_ADA_NEO_1 0x2E
+//! Adafruit NeoTrellis module 2 I2C address
 #define PB_ADDR_ADA_NEO_2 0x2F
+//! Adafruit NeoTrellis module 3 I2C address
 #define PB_ADDR_ADA_NEO_3 0x30
+//! Adafruit NeoTrellis module 4 I2C address
 #define PB_ADDR_ADA_NEO_4 0x32
 
-// Main controller
+//! Main controller I2C address
 #define PB_ADDR_MOD_MAIN 0x08
 
-// Puzzle modules
+//! NeoTrellis puzzle module I2C address
 #define PB_ADDR_MOD_NEOTRELLIS 0x21
+//! Software puzzle module I2C address
 #define PB_ADDR_MOD_SOFTWARE 0x22
+//! Hardware puzzle module I2C address
 #define PB_ADDR_MOD_HARDWARE 0x23
+//! Vault puzzle module I2C address
 #define PB_ADDR_MOD_VAULT 0x24
-// #define BUSADDR_MOD_AUTOMATION 0x25
+//! Automation puzzle module I2C address
+#define BUSADDR_MOD_AUTOMATION 0x25
+//! Dummy puzzle module I2C address
 #define PB_ADDR_MOD_DUMMY 0x69
 
-- 
cgit v1.2.3


From 358bd57295bdda494e11619e2e95bdbe271c0231 Mon Sep 17 00:00:00 2001
From: Loek Le Blansch <loek@pipeframe.xyz>
Date: Fri, 21 Jun 2024 14:17:16 +0200
Subject: merge puzzle module framework and puzzle bus sections

---
 docs/design.adoc | 252 +++++++++++++++++++++++++++----------------------------
 1 file changed, 124 insertions(+), 128 deletions(-)

(limited to 'docs/design.adoc')

diff --git a/docs/design.adoc b/docs/design.adoc
index 7d9759a..6a52b38 100644
--- a/docs/design.adoc
+++ b/docs/design.adoc
@@ -181,10 +181,11 @@ multi-master I^2^C bus, and all puzzle modules are specified to be I^2^C
 multi-master controllers that are slave-addressible. The multi-master part is
 required to prevent I^2^C transmissions from being corrupted in the event of a
 bus collision, and the slave-addressible part is required to both send and
-receive messages on the same controller.
+receive messages on the same controller. This is the only hardware-level
+specification made this year.
 
-Address definitions and protocol specifications are further detailed in
-<<sec:lv2-bus>>.
+More details on the messages sent over the puzzle bus are described in
+<<sec:lv3-pb-messages>>.
 
 === Power supply
 
@@ -260,6 +261,103 @@ designed to facilitate the following:
 * Provide abstracted interfaces to allow for easy integration of the puzzle box
   as part of a larger whole (<<reqs.adoc#req:main-interface>>).
 
+==== Guidelines
+
+The following assumptions are made about puzzle modules:
+
+* Puzzle modules do not take initiative to send REQ or SET commands. They only
+	respond to requests from the main controller.
+* Puzzle modules are I^2^C multi-master controllers that are slave-addressable
+	in master mode.
+* The main controller is a puzzle module, but with the following differences:
+** The main controller is allowed to initiate REQ and SET commands.
+** The main controller's global state is an aggregation of all other puzzle
+	 modules, and ignores STATE SET commands.
+
+These guidelines allow the following simplifications:
+
+* Puzzle modules may assume they are always being addressed by the main
+	controller (this simplifies the message architecture).
+* The puzzle bus may be shared with regular I^2^C peripherals without causing
+	issues.
+
+[[sec:lv3-pb-messages]]
+==== Messages
+
+Puzzle bus messages consist of a simple header and variable data. This format
+is shown in <<tab:pb-msg-fmt>>. The messages are (de)serialized using mpack.
+This choice was made after considering various alternative options for sending
+structured messages cite:[research]. Note that all messages are sent as I^2^C
+writes. Due to this, the I^2^C address of a message sender is included in the
+header.
+
+[[tab:pb-msg-fmt]]
+.Puzzle bus message format
+[%autowidth]
+|===
+| Field | Content
+
+| type | Command type (see <<tab:pb-msg-types>>)
+| action | Command action (see <<tab:pb-msg-actions>>)
+| sender | I^2^C address of sender
+| cmd | Command data (dependent on ``type``)
+|===
+
+<<tab:pb-msg-types>> lists the different command types.
+
+[[tab:pb-msg-types]]
+.Puzzle bus command types
+[cols="10,~"]
+|===
+| Type | Description
+
+| ``MAGIC``
+| The MAGIC command effectively serves as a 'secret handshake' (using a _magic_
+value) which is used to distinguish between puzzle modules and unrelated I^2^C
+devices.
+
+| ``STATE``
+| The STATE command is used by puzzle modules to inform the main controller about
+their global state (see <<sec:framework-state>>). The main controller
+aggregates the states of all connected puzzle modules and exchanges this
+aggregated state with the puzzle modules to indicate when the entire puzzle box
+is solved.
+
+| ``PROP``
+| The PROP command type is used for exchanging arbitrary data between puzzle
+modules and/or the puzzle box client (pbc) over the <<sec:main-bridge,TCP
+bridge>>. These properties are not used by the puzzle framework.
+|===
+
+<<tab:pb-msg-actions>> lists the different command actions.
+
+[[tab:pb-msg-actions]]
+.Puzzle bus command actions
+[cols="10,~"]
+|===
+| ``REQ``
+| Mark the command as a request. The receiver of this message is expected to
+return a message of the same type, but with a RES action.
+
+| ``RES``
+| Mark the command as a response to a REQ message. All REQ messages should be
+followed by a RES message.
+
+| ``SET``
+| Request a change / write. The SET command is never followed by a RES.
+|===
+
+Please note that not all commands define behavior for all actions (e.g. there
+is no MAGIC SET command).
+
+Only the MAGIC and STATE commands are required for the puzzle box to function.
+The PROP command was created to allow future expansion without modifying the
+main controller firmware (<<reqs.adoc#req:main-static>>).
+
+The specific format of the 'cmd' field from <<tab:pb-msg-fmt>> is different for
+each command type, and is for this reason only documented in-code using
+Doxygen.
+
 [[sec:framework-state]]
 ==== State
 
@@ -267,20 +365,21 @@ All puzzle modules implement the same state machine shown in
 <<fig:puzzle-module-common-state>>. Note that continuous arrows indicate state
 transitions that a puzzle module may take on its own, while dashed arrows
 indicate state transitions forced by the main controller. The main controller
-also allows the game operator to manually set a module''s global state to one of
+also allows the game operator to manually set a module's global state to one of
 these states, which can be used to skip a puzzle if a player is stuck
 (<<reqs.adoc#req:edge-skip-puzzle>>) or reset a game if it is malfunctioning
 (<<reqs.adoc#req:edge-manual-reset>>).
 
-Puzzle modules start in the 'uninitialized' state, where they wait until the
-main controller sends a SET STATE command. Receiving this command indicates to
-the puzzle module that it was successfully registered by the main controller,
-and that it may transition from the 'uninitialized' state to the 'idle' state.
-
 [[fig:puzzle-module-common-state]]
 .Global puzzle module state machine
 image::img/puzzle-module-common-state.svg[]
 
+Puzzle modules start in the 'uninitialized' state, where they wait until the
+main controller sends a REQ STATE command. Receiving this command indicates to
+the puzzle module that it was successfully registered by the main controller,
+and that it may transition from the 'uninitialized' state to the 'idle' state.
+This process is also shown in <<fig:sequence-puzzle-module-init>>.
+
 The state machine described in <<fig:puzzle-module-common-state>> is referred
 to as the global state. Puzzle modules may also declare and define custom
 variables, which are referred to as properties. These properties may contain
@@ -289,79 +388,23 @@ puzzle module, or the last passcode entered on the vault puzzle module.
 
 Separating properties from the global state allows the main controller to
 handle these property values as an arbitrary blob, which allows for future
-expansion without modification of the main controller software.
-
-==== Commands
-
-// TODO: cleanup
-
-All messages sent over the puzzle bus have a similar format. This format is
-shown in Table 2. Notable details include:
-
-The 'subject' field does not have to match the I^2^C address of the message
-sender or recipient
-
-Property 0x00 stores a module's global state
-
-.Puzzle bus message format
-[%autowidth]
-|===
-| Field | Content
-
-| Command | Enum: read, write, update
-| Subject | I^2^C address (7-bit)
-| Property | Address (8-bit)
-| Value | Byte string (variable length)
-|===
-
-The messages described in Table 2 are (de)serialized using Google's protocol
-buffer library. This choice was made after considering various alternative
-options for sending structured messages cite:[research].
-
-<<fig:sequence-puzzle-module-init>> shows an example of how messages are
-exchanged for the initialization of a puzzle module.
-
-<<fig:sequence-puzzle-finish>> shows an example exchange where the last puzzle
-module (A) is solved while (B) is already solved.
-
-. First, module A sets it's own state to 'solved' and subsequently informs the
-  main controller of this change.
-. As a result of this update notification, the main controller queries puzzle
-  module A for its new global state.
-. Once the main controller has received and confirmed that all puzzle module
-  global states are set to 'solved', the main controller sets its own state to
-  'solved', and broadcasts an update message to all puzzle modules.
-. As a result of the update message from the main controller, module B requests
-  the main controller's new global state, and is able to verify that all puzzle
-  modules have been solved.
+expansion without modification of the main controller software
+(<<reqs.adoc#req:main-static>>).
 
-In this example, module B could be the vault puzzle module, which displays a
-code when the entire puzzle box is solved.
+==== I^2^C addresses
 
-[[fig:sequence-puzzle-finish]]
-.Puzzle box finish sequence diagram
-image::img/sequence-puzzle-finish.svg[]
-
-The puzzle module framework describes the following command _types_:
-
-* ``PROP``: property
-* ``MAGIC``: handshake
-* ``STATE``: global state
-
-Each command also has a specific _action_:
-
-* ``REQ``: request
-* ``RES``: response
-* ``SET``: (over)write
+The RPI Pico SDK prohibits the use of I^2^C addresses reserved by the I^2^C
+specification. This means different addresses from previous years are used.
+These addresses are indexed in the code under a shared header (see
+``lib/pbdrv/pb.h``).
 
-- Not all commands define behavior for all actions (e.g. there is no MAGIC SET
-	command).
-- A REQ command is always answered by a RES command.
-- A SET command does not have a reply.
-- All commands are sent as I^2^C writes.
+The same I^2^C address may be used by two different puzzle modules, but this
+will make it impossible for them to be used simultaniously.
 
-The Doxygen-generated pages for these command types explain their usage, and
-will not be restated in this document.
+The I^2^C addresses are also used to determine the puzzle sequence (i.e. the
+order in which puzzle modules are set to the 'playing' state). The sequence is
+determined by the main controller on startup, and consists of the connected
+puzzle modules' addresses in descending order (i.e. highest address first).
 
 === Main Controller
 
@@ -370,11 +413,9 @@ This subsection defines the function and state of the main controller.
 ==== Initializing puzzle modules
 
 The main controller sends a MAGIC REQ command to every I^2^C address on
-startup. The MAGIC command effectively serves as a 'secret handshake' (using a
-_magic_ value) which is used to distinguish between puzzle modules and
-unrelated I^2^C devices. Puzzle modules start in the 'uninitialized' state (see
-<<fig:puzzle-module-common-state>>), in which they do nothing. Puzzle modules
-in this state are still able to reply to requests, including MAGIC REQ
+startup. Puzzle modules start in the 'uninitialized' state (see
+<<fig:puzzle-module-common-state>>), during which they do nothing. Puzzle
+modules in this state are still able to reply to requests, including MAGIC REQ
 commands. When the main controller receives a MAGIC RES command, the I^2^C
 address of the sender is added to an internal list for puzzle modules.
 
@@ -452,51 +493,6 @@ TODO
 - puzzle bus driver functions can no longer be called directly from ISR handlers due to the delay
 - FreeRTOS is also used in puzzle modules, though this can likely be removed in the future
 
-[[sec:lv2-bus]]
-=== Puzzle bus
-
-This section describes the addresses and communication protocol used on the
-puzzle bus. These specifications only apply to messages sent internally in the
-puzzle box, as messages forwarded by the bridge (see <<sec:main-bridge>>) are
-sent on behalf of the main controller.
-
-==== Guidelines
-
-The following assumptions are made about puzzle modules:
-
-* Puzzle modules do not take initiative to send REQ or SET commands. They only
-	respond to requests from the main controller.
-* Puzzle modules can be distinguished from unrelated I^2^C peripherals using
-	the MAGIC command.
-* Puzzle modules are I^2^C multi-master controllers that are slave-addressable
-	in master mode.
-* The main controller is a puzzle module, but with the following differences:
-** The main controller is allowed to initiate REQ and SET commands.
-** The main controller's global state is an aggregation of all other puzzle
-	 modules, and ignores STATE SET commands.
-
-These guidelines allow the following simplifications:
-
-* Puzzle modules may assume they are always being addressed by the main
-	controller (this simplifies the message architecture).
-* The puzzle bus may be shared with regular I^2^C peripherals without causing
-	issues.
-
-==== Addresses
-
-The RPI Pico SDK prohibits the use of I^2^C addresses reserved by the I^2^C
-specification. This means different addresses from previous years are used.
-These addresses are indexed in the code under a shared header (see
-``lib/pbdrv/pb.h``).
-
-The same I^2^C address may be used by two different puzzle modules, but this
-will make it impossible for them to be used simultaniously.
-
-The I^2^C addresses are also used to determine the puzzle sequence (i.e. the
-order in which puzzle modules are set to the 'playing' state). The sequence is
-determined by the main controller on startup, and consists of the connected
-puzzle modules' addresses in descending order (i.e. highest address first).
-
 === NeoTrellis puzzle
 
 This subsection defines aspects of the 'NeoTrellis puzzle' module and gives a
-- 
cgit v1.2.3


From 8bd40843cbaafd82e11d897fe210c0975b5bd73c Mon Sep 17 00:00:00 2001
From: Loek Le Blansch <loek@pipeframe.xyz>
Date: Fri, 21 Jun 2024 15:43:00 +0200
Subject: add disclaimers

---
 .editorconfig       |  2 +-
 docs/design.adoc    |  8 +++++++-
 docs/handover.adoc  | 11 ++++++-----
 docs/reqs.adoc      | 40 ++++++++++++++++++++--------------------
 docs/research.adoc  | 19 +++++++++++++++----
 docs/share/refs.bib |  8 ++++++++
 docs/theme.yml      |  8 ++++++++
 7 files changed, 65 insertions(+), 31 deletions(-)

(limited to 'docs/design.adoc')

diff --git a/.editorconfig b/.editorconfig
index cd37156..bd1f474 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -5,7 +5,7 @@ indent_style = tab
 end_of_line = lf
 insert_final_newline = true
 
-[*.md]
+[*.{md,yml}]
 indent_style = space
 indent_size = 2
 
diff --git a/docs/design.adoc b/docs/design.adoc
index 6a52b38..06cd100 100644
--- a/docs/design.adoc
+++ b/docs/design.adoc
@@ -146,7 +146,13 @@ The criteria for the main controller are:
 The requirements document compares various microcontrollers that fit these
 criteria. After this comparison, the decision was made to utilize the Raspberry
 Pi Pico W as main controller during development.
-// TODO: this was a bad choice
+
+NOTE: This was written while we did not know the puzzle bus specifically
+requires slave-addressible I^2^C multi-master controllers to function properly.
+While the research concludes the RP2040 is a suitable microcontroller for the
+main controller, it is not. The RP2040 was still used, but has required
+implementing workarounds. Please see the handover report for more details on
+how this impacted the project cite:[handover].
 
 [[fig:main-controller-top]]
 .Main controller top-level block diagram
diff --git a/docs/handover.adoc b/docs/handover.adoc
index 6918256..77d5da0 100644
--- a/docs/handover.adoc
+++ b/docs/handover.adoc
@@ -29,16 +29,17 @@ removal or transfer of these files.
 
 [[tab:proj-comp]]
 .Project group composition
+[cols="15,35,20",width=55%]
 |===
 | Year | Name | Study path
 
-.4+| 19-20
+.4+h| 19-20
 | Daniël Janssen | Software
 | Dion Legierse | Software
 | Jop van Laanen | Hardware
 | Max van den Heijkant | Software
 
-.4+| 20-21
+.4+h| 20-21
 | Joost van Wiechen | Hardware
 | Justin Maas | Software
 | [[pn:creemers,Merel Creemers]]Merel Creemers | Hardware{empty}footnote:[The
@@ -51,18 +52,18 @@ were a hardware student that worked on the PCBs or a CMD student working on the
 puzzle box chassis.]
 | Vincent Lengowski | Hardware
 
-.5+| 21-22
+.5+h| 21-22
 | Alex van Kuijk | Hardware
 | Jef Baars | Software
 | Julian de Bruin | Software
 | Lucas van Gastel | Software
 | Toon Rockx | Hardware
 
-.2+| 22-23
+.2+h| 22-23
 | Frank Bekema | Hardware
 | Jasper Gense | Hardware
 
-.4+| 23-24
+.4+h| 23-24
 | Elwin Hammer | Software
 | [[pn:faase,Lars Faase]]Lars Faase{empty}footnote:[<<pn:faase>> was removed
 from the project group on 2024-06-03 following complaints about the lack of
diff --git a/docs/reqs.adoc b/docs/reqs.adoc
index 8ad24a8..611c8f3 100644
--- a/docs/reqs.adoc
+++ b/docs/reqs.adoc
@@ -108,7 +108,7 @@ describes all functional requirements of the puzzle box.
 === The puzzle box
 
 .Puzzle box specifications
-[cols="8h,5h,~"]
+[cols="9h,6h,~"]
 |===
 | ID | <<tab:moscow,Pri.>> | Specification
 
@@ -165,7 +165,7 @@ describes all functional requirements of the puzzle box.
 === The bomb
 
 .Bomb specifications
-[cols="8h,5h,~"]
+[cols="9h,6h,~"]
 |===
 | ID | <<tab:moscow,Pri.>> | Specification
 
@@ -198,7 +198,7 @@ describes all functional requirements of the puzzle box.
 === The game
 
 .General game specifications
-[cols="8h,5h,~"]
+[cols="9h,6h,~"]
 |===
 | ID | <<tab:moscow,Pri.>> | Specification
 
@@ -239,7 +239,7 @@ describes all functional requirements of the puzzle box.
 ==== NeoTrellis puzzle
 
 .NeoTrellis puzzle requirements
-[cols="8h,5h,~"]
+[cols="9h,6h,~"]
 |===
 | ID | <<tab:moscow,Pri.>> | Specification
 
@@ -262,7 +262,7 @@ describes all functional requirements of the puzzle box.
 ==== Software puzzle
 
 .Software puzzle requirements
-[cols="8h,5h,~"]
+[cols="9h,6h,~"]
 |===
 | ID | <<tab:moscow,Pri.>> | Specification
 
@@ -297,7 +297,7 @@ The specific details for this puzzle are not present in the previous
 documentation. Due to time constraints, the section will be left empty.
 
 .Automation puzzle requirements
-[cols="8h,5h,~"]
+[cols="9h,6h,~"]
 |===
 | ID | <<tab:moscow,Pri.>> | Specification
 
@@ -308,7 +308,7 @@ documentation. Due to time constraints, the section will be left empty.
 ==== Hardware puzzle
 
 .Hardware puzzle requirements
-[cols="8h,5h,~"]
+[cols="9h,6h,~"]
 |===
 | ID | <<tab:moscow,Pri.>> | Specification
 
@@ -397,7 +397,7 @@ documentation. Due to time constraints, the section will be left empty.
 ==== Vault puzzle
 
 .Vault puzzle requirements
-[cols="8h,5h,~"]
+[cols="9h,6h,~"]
 |===
 | ID | <<tab:moscow,Pri.>> | Specification
 
@@ -447,7 +447,7 @@ documentation. Due to time constraints, the section will be left empty.
 === Battery
 
 .Battery requirements
-[cols="8h,5h,~"]
+[cols="9h,6h,~"]
 |===
 | ID | <<tab:moscow,Pri.>> | Specification
 
@@ -464,7 +464,7 @@ documentation. Due to time constraints, the section will be left empty.
 === Network Communication
 
 .Communication requirements
-[cols="8h,5h,~"]
+[cols="9h,6h,~"]
 |===
 | ID | <<tab:moscow,Pri.>> | Specification
 
@@ -477,7 +477,7 @@ documentation. Due to time constraints, the section will be left empty.
 
 === Framework
 
-[cols="8h,5h,~"]
+[cols="9h,6h,~"]
 |===
 | ID | <<tab:moscow,Pri.>> | Specification
 
@@ -497,7 +497,7 @@ documentation. Due to time constraints, the section will be left empty.
 === Puzzle box hub
 
 .Puzzle box hub general requirements
-[cols="8h,5h,~"]
+[cols="9h,6h,~"]
 |===
 | ID | <<tab:moscow,Pri.>> | Specification
 
@@ -516,7 +516,7 @@ technical specifications of the puzzle box.
 === Wireless communication
 
 .Wireless communication requirements
-[cols="8h,5h,~"]
+[cols="9h,6h,~"]
 |===
 | ID | <<tab:moscow,Pri.>> | Specification
 
@@ -527,7 +527,7 @@ technical specifications of the puzzle box.
 === Framework
 
 .Development framework requirements
-[cols="8h,5h,~"]
+[cols="9h,6h,~"]
 |===
 | ID | <<tab:moscow,Pri.>> | Specification
 
@@ -550,7 +550,7 @@ technical specifications of the puzzle box.
 === Main controller
 
 .Main controller requirements
-[cols="8h,5h,~"]
+[cols="9h,6h,~"]
 |===
 | ID | <<tab:moscow,Pri.>> | Specification
 
@@ -575,7 +575,7 @@ technical specifications of the puzzle box.
 
 === Puzzle module controller
 
-[cols="8h,5h,~"]
+[cols="9h,6h,~"]
 |===
 | ID | <<tab:moscow,Pri.>> | Specification
 
@@ -601,7 +601,7 @@ technical specifications of the puzzle box.
 === Vault puzzle
 
 .Vault puzzle requirements
-[cols="8h,5h,~"]
+[cols="9h,6h,~"]
 |===
 | ID | <<tab:moscow,Pri.>> | Specification
 
@@ -627,7 +627,7 @@ technical specifications of the puzzle box.
 === Bomb
 
 .Bomb requirements
-[cols="8h,5h,~"]
+[cols="9h,6h,~"]
 |===
 | ID | <<tab:moscow,Pri.>> | Specification
 
@@ -650,7 +650,7 @@ This section describes the aspects of the project which have been set as
 preconditions and cannot be changed.
 
 .Preconditions
-[cols="8h,~"]
+[cols="9h,~"]
 |===
 | ID | Precondition
 
@@ -666,7 +666,7 @@ preconditions and cannot be changed.
 This section lists requirements that apply to documentation produced during
 this project.
 
-[cols="8h,5h,~"]
+[cols="9h,6h,~"]
 |===
 | ID | <<tab:moscow,Pri.>> | Specification
 
diff --git a/docs/research.adoc b/docs/research.adoc
index 753206c..acab4ab 100644
--- a/docs/research.adoc
+++ b/docs/research.adoc
@@ -143,6 +143,13 @@ than the other options. It also happens to be less expensive than all other
 options. Due to these reasons, the RP2040 was chosen as main controller MCU.
 The Raspberry Pi Pico W board is utilized during development.
 
+NOTE: This was written while we did not know the puzzle bus specifically
+requires slave-addressible I^2^C multi-master controllers to function properly.
+While the research concludes the RP2040 is a suitable microcontroller for the
+main controller, it is not. The RP2040 was still used, but has required
+implementing workarounds. Please see the handover report for more details on
+how this impacted the project cite:[handover].
+
 [[tab:main-mcu]]
 .Main controller MCU candidates
 [%autowidth]
@@ -173,10 +180,10 @@ manufacturers: Atmel, STMicroelectronics, Raspberry Pi.
 
 All the MCUs listed in <<tab:pm-mcu>> support some version of a low-power mode.
 The RP2040 is again included and appears here because it supports clock speed
-configuration and has a clock gate for each peripheral [2], which may make it a
-feasible option with regards to power consumption. Choosing the RP2040 may also
-simplify the development process as only a single MCU toolchain needs to be
-maintained.
+configuration and has a clock gate for each peripheral cite:[rp2040ds], which
+may make it a feasible option with regards to power consumption. Choosing the
+RP2040 may also simplify the development process as only a single MCU toolchain
+needs to be maintained.
 
 The Microchip PIC16F15276 is the most power efficient on this list and is the
 recommended MCU for puzzle modules. It supports both extreme underclocking and
@@ -187,6 +194,10 @@ Because this year's run of this project was carried out by a team consisting
 only of software students, this choice remains as a recommendation. The puzzle
 box hardware may still use the ESP32 development kits from the 21-22 group.
 
+NOTE: This was written while we did not know the puzzle bus specifically
+requires slave-addressible I^2^C multi-master controllers to function properly.
+We have not verified if the PIC16F15276 supports this feature.
+
 [[tab:pm-mcu]]
 .Puzzle module controller MCU candidates
 [%autowidth]
diff --git a/docs/share/refs.bib b/docs/share/refs.bib
index b6fe625..1c37465 100644
--- a/docs/share/refs.bib
+++ b/docs/share/refs.bib
@@ -166,6 +166,14 @@
 	year = {2024},
 }
 
+@techreport{handover,
+	author = {Blansch, Loek Le and Hammer, Elwin and Faase, Lars and in 't Anker, Thomas},
+	title = {Handover Report},
+	location = {'s-Hertogenbosch},
+	publisher = {Avans University of Applied Sciences},
+	year = {2024},
+}
+
 @techreport{2021_design,
 	author = {Creemers, Merel and van Wiechen, Joost and Lengowski, Vincent and Maas, Justin},
 	title = {Ontwerpdocument},
diff --git a/docs/theme.yml b/docs/theme.yml
index b26ad75..49f729f 100644
--- a/docs/theme.yml
+++ b/docs/theme.yml
@@ -61,6 +61,7 @@ toc:
 caption:
   align: center
   end: bottom
+  margin_inside: 6pt
 
 image:
   align: center
@@ -98,3 +99,10 @@ footer:
     center:
       content: '{page-number}'
 
+admonition:
+  column_rule_color: '#000000'
+  column_rule_width: 1pt
+  padding: [3pt, 6pt, 3pt, 6pt]
+  label:
+    font_style: bold
+
-- 
cgit v1.2.3


From 79e60b430143b2acc4b93f62e23770e6bcbd7861 Mon Sep 17 00:00:00 2001
From: Loek Le Blansch <loek@pipeframe.xyz>
Date: Fri, 21 Jun 2024 16:31:43 +0200
Subject: design doc TODOs done

---
 docs/design.adoc | 26 ++++++++++++++------------
 docs/reqs.adoc   |  5 ++++-
 2 files changed, 18 insertions(+), 13 deletions(-)

(limited to 'docs/design.adoc')

diff --git a/docs/design.adoc b/docs/design.adoc
index 06cd100..9e48fd4 100644
--- a/docs/design.adoc
+++ b/docs/design.adoc
@@ -486,18 +486,20 @@ Detailed specifications on the TCP socket server are in
 
 ==== Operating system
 
-TODO
-
-- main controller does tcp and i2c at the same time
-- simple scheduler is needed
-- curriculum only has FreeRTOS and Zephyr
-- Zephyr is overkill
-- FreeRTOS it is
-
-- due to RP2040 limitations, delays are used
-- most SDKs I2C drivers directly call I2C message handlers from ISR
-- puzzle bus driver functions can no longer be called directly from ISR handlers due to the delay
-- FreeRTOS is also used in puzzle modules, though this can likely be removed in the future
+Because the main controller needs to asynchronously handle state exchanges with
+puzzle modules while serving a TCP socket connection, the decision to use a
+task scheduler was made. Due to the requirement that most software should be
+covered by the standard curriculum (<<reqs.adoc#req:curriculum-cov>>), this
+choice was between FreeRTOS and Zephyr. FreeRTOS was chosen because it is the
+simplest solution, and because the features Zephyr offers over FreeRTOS are
+already present in the Raspberry Pi Pico SDK.
+
+NOTE: Due to the issues with the RP2040 that were later discovered
+cite:[handover], delays are used within the puzzle bus driver's message
+handling logic. This means that due to the use of the RP2040, *all puzzle
+modules* are required to use a task scheduler or similar mechanism for
+deferring calls to the puzzle bus driver from the I^2^C interrupt service
+routine (ISR).
 
 === NeoTrellis puzzle
 
diff --git a/docs/reqs.adoc b/docs/reqs.adoc
index 611c8f3..a221173 100644
--- a/docs/reqs.adoc
+++ b/docs/reqs.adoc
@@ -543,8 +543,11 @@ technical specifications of the puzzle box.
 | <<req:135>> | <<must>> |
 [[req:135,R-135]] Puzzle modules are initialized by the main controller module.
 
-| <<req:165>> | <<must>> |
+| <<req:165>> | <<wont>> |
 [[req:165,R-165]] Puzzle modules repeatedly send 'update' messages to the main controller while their global state is 'uninitialized'
+
+| <<req:curriculum-cov>> | <<should>> |
+[[req:curriculum-cov,R-169]] External software and libraries that are covered in the standard curriculum should be used where possible
 |===
 
 === Main controller
-- 
cgit v1.2.3

