aboutsummaryrefslogtreecommitdiff
path: root/docs/design.adoc
diff options
context:
space:
mode:
Diffstat (limited to 'docs/design.adoc')
-rw-r--r--docs/design.adoc568
1 files changed, 568 insertions, 0 deletions
diff --git a/docs/design.adoc b/docs/design.adoc
new file mode 100644
index 0000000..5ebbb15
--- /dev/null
+++ b/docs/design.adoc
@@ -0,0 +1,568 @@
+:document: Software Design
+include::share/meta.adoc[]
+
+== Introduction
+
+This document contains all the design considerations made for the separate
+software components that make up the puzzle box. This document has a top-down
+structure, and has three levels of design 'depth':
+
+. Top-level (hardware diagrams, OSes, communication buses, etc.)
+. Module-level (puzzle inputs/outputs, top-level software diagram, etc.)
+. Component-level (software dependencies, game state, etc.)
+
+Only design details deemed relevant by the document authors are documented
+here. Low-level implementation details such as API interfaces, code paths and
+workarounds are documented inside the source code repository.
+
+[[sec:lv1]]
+== Top-Level
+
+This section of the design document establishes the development target
+hardware. It also specifies the modules that are elaborated further in
+<<sec:lv2>>.
+
+<<fig:system-top>> shows a block diagram that describes the context in which
+the puzzle box is used. The puzzle box in this diagram internally consists of a
+main controller and multiple puzzle modules. Other notable details include:
+
+* The charger is removable, and the puzzle box is intended to be used as a
+ battery-powered device (i.e. not while tethered).
+* Puzzle outputs are used to complete a feedback loop (gameplay) with the
+ players, as well as eventually provide a solution to diffuse a bomb. This
+ bomb is part of a standalone project that has already been finished at the
+ time of writing (2024-03-11), and this project only describes the interface
+ between the puzzle box and the bomb.
+* The puzzle box is capable of bidirectional communication over Wi-Fi. This
+ connection is used to configure the puzzle box before gameplay or modify its
+ state during gameplay.
+
+[[fig:system-top]]
+.Context block diagram
+image::img/system-top.svg[]
+
+The rest of this section details the internal hardware modules and the
+separation of functionality of these modules.
+
+=== Puzzle Modules
+
+The puzzle box hardware produced by the 21-22 group consists of 6 sides, 4 of
+which are utilized by puzzle modules. This section defines the properties of a
+puzzle module.
+
+Puzzle modules can occupy one or more physical sides of the puzzle box to
+implement the physical interface required for a puzzle or game. In order to
+realize a complete game, each of these puzzle modules must have the ability to
+control game inputs and outputs. Two approaches for this were considered:
+
+. Let the main controller handle game state and logic for all puzzle modules.
++
+This approach has the main benefit of allowing puzzle module controllers to be
+substituted for I^2^C I/O expanders that draw less power than a complete MCU.
++
+The major drawback of this approach is that the main controller's software
+needs to be configured for each different hardware configuration, which makes
+the main controller software more complicated.
+
+. Design an abstract 'game interface' and give each puzzle module its own MCU.
++
+This approach provides the most flexibility, as the main controller's software
+is no longer dependent on the physically installed hardware. This approach is
+also favorable with regards to testability, as each puzzle module can run
+standalone.
++
+The main drawback of this approach is the possible increase in power
+consumption, as each puzzle module now must have its own MCU for managing game
+state and communication with the main controller.
+
+The current hardware (developed by the 21-22 group) uses the second approach,
+though with MCUs that were not designed for power efficiency. This year
+(23-24), the hardware produced by the 21-22 group was utilized due to the 23-24
+group not including students from the hardware study path. Minimizing power
+draw for each puzzle module is still a priority, so a different microcontroller
+was selected.
+
+The criteria for a puzzle module controller are:
+
+* Must have an I^2^C peripheral (<<reqs.adoc#req:pm-i2c-ctrl>>).
+* Should have enough I/O ports to directly control moderately complex puzzles
+ (<<reqs.adoc#req:pm-gpio>>).
+* Should be power efficient (<<reqs.adoc#req:pm-pwr-efficient>>).
+
+The research document cite:[research] compares various microcontrollers
+matching these criteria. As a result of this research, the Microchip
+PIC16F15276 was selected as the recommended microcontroller for future puzzle
+modules. The current development hardware utilizes an ESP32-PICO-D4 module, so
+the puzzle module software is written with portability in mind.
+
+[[fig:puzzle-module-top]]
+.Generic puzzle module top-level block diagram
+image::img/puzzle-module-top.svg[]
+
+<<fig:puzzle-module-top>> shows a block diagram of how most puzzle modules are
+implemented. Since the internal components of the puzzle module block from
+<<fig:puzzle-module-top>> differ for each puzzle, they are left out in this
+section. <<sec:lv2>> includes the next detail level for all of the implemented
+puzzles this year. The puzzle bus is detailed further in
+<<sec:lv1-communication>>.
+
+=== Main Controller
+
+This section describes the responsibilities of the main controller inside the
+puzzle box. The main controller is a central processor that is responsible for
+the following:
+
+* Integrate installed puzzle modules to form a cohesive experience by—
+** Detecting and initializing installed puzzle modules.
+** 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—
+** Sending state updates
+** Manually updating game state
+** Integration with the bomb
+
+The specific requirement of being able to serve TCP socket connections was
+created so this year's puzzle box could keep compatibility with the software
+produced by the 21-22 group.
+
+As mentioned in the research document cite:[research], the 21-22 group produced
+the hardware that is used as development target for this year's (23-24) run of
+the puzzle box project. The existing hardware utilizes a Raspberry Pi 3B+ as
+main controller, but this controller caused issues with power consumption
+cite:[2122_handover]. Choosing a different controller during development
+requires significant refactoring, so a different main controller has been
+selected at the start of this year's run of the puzzle box project.
+
+The criteria for the main controller are:
+
+* Must have an I^2^C peripheral (<<reqs.adoc#req:main-i2c-ctrl>>).
+* Must be able to connect to a standard 802.11b/g/n access point
+ (<<reqs.adoc#req:main-802-11-ap>>).
+* Must be able to serve TCP socket connection(s)
+ (<<reqs.adoc#req:main-tcp-socket>>).
+* Should be power efficient (<<reqs.adoc#req:main-pwr-efficient>>).
+
+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.
+
+[[fig:main-controller-top]]
+.Main controller top-level block diagram
+image::img/main-controller-top.svg[]
+
+<<fig:main-controller-top>> shows a block diagram of the main controller and
+its inputs and outputs. The main controller is the only module in the puzzle
+box that is able to communicate over Wi-Fi and is therefore responsible for all
+communication between the puzzle box and game operator. The puzzle bus is
+detailed further in <<sec:lv1-communication>>.
+
+[[sec:lv1-communication]]
+=== Communication
+
+Communication between puzzle modules, the main controller and other auxiliary
+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].
+
+Address definitions and protocol specifications are further detailed in
+<<sec:lv2-bus>>.
+
+=== Power supply
+
+One of the user requirements is that the puzzle box runs on battery power
+(<<reqs.adoc#req:pwr-battery>>). Due to the team composition of this year's
+(23-24) run of the puzzle box project, a new power supply was not chosen, even
+though the current power supply was determined insufficient by the 21-22 group.
+This year, additional requirements were specified for the power supply, which
+were used when selecting MCUs suitable for battery-powered applications.
+
+[[fig:power-supply-top]]
+.Power supply module top-level block diagram
+image::img/power-supply-top.svg[]
+
+<<fig:puzzle-module-top>> shows a block diagram of how most puzzle modules are
+implemented. Besides the additional requirements, the power supply remains the
+same, and will not be elaborated further on in this document.
+
+=== Overview
+
+<<fig:system-bus>> is the resulting combination of the modules from
+<<fig:puzzle-module-top>>, <<fig:main-controller-top>> and
+<<fig:power-supply-top>>.
+
+[[fig:system-bus]]
+.Hardware component overview
+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.
+
+=== 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.
+
+The puzzle framework is the foundation of the puzzle box software, and is
+designed to facilitate the following:
+
+* Allow puzzle modules to be swapped with minimal downtime or maintenance
+ (<<reqs.adoc#req:pm-swap>>).
+* Simplify the development process and integration of new puzzle modules
+ (<<reqs.adoc#req:main-static>>).
+* Provide abstracted interfaces to allow for easy integration of the puzzle box
+ as part of a larger whole (<<reqs.adoc#req:main-interface>>).
+
+[[sec:framework-state]]
+==== 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]]
+.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.
+
+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.
+
+==== Commands
+
+The puzzle module framework describes the following commands:
+
+* Read state
+* Write state
+* Update
+
+The 'read' and 'write' commands are used to communicate both types of state
+defined in <<sec:framework-state>>.
+
+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.
+
+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.
+
+=== Main Controller
+
+This subsection defines the function and state of the main controller.
+
+==== 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
+<<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:
+
+* 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 'solved' state, the main controller is also
+ 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)
+
+[[sec:main-bridge]]
+==== Bridge
+
+The bridge is used to remotely access and control the puzzle box.
+
+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>>).
+
+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
+
+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.
+
+[[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.
+
+==== 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
+
+.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[]
+
+=== 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
+facilitate the NeoTrellis puzzle game logic and communication with the main
+controller about the puzzle state.
+
+==== NeoTrellis puzzle gameplay
+
+The NeoTrellis puzzle is an 8x8 button matrix with Neopixels underneath each
+button. The way to solve this puzzle is by dimming every Neopixel in the 8x8
+matrix. This is done by clicking on a button, which switches the state of the
+Neopixel underneath the pixel and the Neopixels in each cardinal direction from
+the pressed button. This means that if a Neopixel was on and the button was
+pressed it will turn off and vice-versa. A visual example can be found in
+Appendix B.
+
+==== Puzzle inputs & outputs
+
+The inputs and outputs of this puzzle have been taken from the design document
+of the previous group which worked on this project (??). This input and output
+diagram has been shown in <<fig:neotrellis-io>>.
+
+[[fig:neotrellis-io]]
+.NeoTrellis puzzle in-out
+image::img/neotrellis-io.png[]
+
+=== 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
+facilitate the software puzzle game logic and communication with the main
+controller about the software puzzle state.
+
+[[sec:software-gameplay]]
+==== Software puzzle gameplay
+
+The software puzzle consists of 12 input ports which can be connected using a
+banana plug connector. The 6 input ports on the left side of the puzzle each
+have their own logical circuit engraved in the box, and the 6 input ports on
+the right side of the puzzle have a letter (A through F) engraved in the box.
+The way to solve the puzzle is by connecting the banana plug cable from an
+input port on the left side of the puzzle to the corresponding input port on
+the right side of the puzzle. An example of this can be found in Appendix C.
+
+When the puzzle starts, the participants of the game will have 6 code-fragments
+written on paper, corresponding to the logical circuits on the puzzle box. The
+bomb participants will have description of the C-code fragments, while the
+puzzle box participants only have the logical circuits on the puzzle box. The
+participants must communicate with each other to figure out which a fragment of
+C code corresponds with a logical circuit engraved on the puzzle box. Once this
+has been done the puzzle box participants can use a banana plug cable to
+connect the input and output to each other. Once the correct combination of
+logical gates with the correct letter is made, the puzzle is solved (shown by
+an LED lighting up above the puzzle). Allowing the participants to both see a
+binary code using 16 LEDs above the puzzle, and to continue to the next puzzle.
+
+==== Puzzle inputs & outputs
+
+As stated in <<sec:software-gameplay>> the puzzle has 12 inputs, as well as an
+LED which shows whether the puzzle has been solved and 16 LEDs showing a binary
+code. This is shown in <<fig:software-io>>.
+
+[[fig:software-io]]
+.Software puzzle in-out
+image::img/software-io.png[]
+
+=== Hardware Puzzle
+
+==== 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
+correct position. To solve the puzzle, a truth table is used.
+
+The second part of the puzzle is unlocked after solving the logic gate puzzle,
+the user has to listen to a Morse code from which a four-digit code follows.
+The user then turns potentiometers to change this code on the display. The
+puzzle is solved when the user has put the correct code on the display. Once
+successful, the indicator LED will light up.
+
+==== Puzzle inputs / outputs
+
+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 gameplay
+
+The vault puzzle is a puzzle created to test the communication skills of the
+student. It shows a code on the puzzle box, which then needs to be given to
+students with the game manual, who communicates this to the students at the
+puzzle box the button they must click. This needs to be done 5 times before the
+vault opens and the last code is given to defuse the bomb if a wrong button is
+clicked the vault resets and they need to start over from the beginning.
+
+==== Puzzle inputs & outputs
+
+[[fig:vault-io]]
+.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
+
+[appendix]
+== NeoTrellis puzzle example
+
+[appendix]
+== Software puzzle example
+
+include::share/footer.adoc[]