diff --git a/moana/index.html b/moana/index.html
index 119e4e8..7cddc7a 100644
--- a/moana/index.html
+++ b/moana/index.html
@@ -189,6 +189,12 @@ pre {
Doolhof |
+
+ 1 |
+ Zeus WPI |
+ Spectroscopy Amplifier (model 2020) |
+
+
255 |
private use |
diff --git a/src/modules/puzzle_spectroscopy_amplifier/doc/index.md b/src/modules/puzzle_spectroscopy_amplifier/doc/index.md
new file mode 100644
index 0000000..9448501
--- /dev/null
+++ b/src/modules/puzzle_spectroscopy_amplifier/doc/index.md
@@ -0,0 +1,20 @@
+# Spectroscopy Amplifier (model 2020)
+
+Schrijf de handleiding voor je module hier. Kijk gerust naar de handleiding
+voor de "Doolhof"-module (`src/modules/puzzle_maze/doc/index.md`)
+
+
+Hieronder wat voorbeelden van markup die je kan gebruiken. Daarnaast kan je ook LaTeX
+gebruiken (zie bijvoorbeeld de "Doolhof"-module)
+
+Use drawings! Create the docs/images/your_module directory, put your image there and include them like this:
+
+![](./your_module/filename.png)
+
+Use tables! Write them like this:
+
+| Symbol | Action to take |
+|--------------------------------|----------------|
+| ![](./your_module/symbol1.png) | Do nothing |
+| ![](./your_module/symbol2.png) | Press the red button |
+| ![](./your_module/symbol3.png) | Press the yellow button |
diff --git a/src/modules/puzzle_spectroscopy_amplifier/puzzle_spectroscopy_amplifier.ino b/src/modules/puzzle_spectroscopy_amplifier/puzzle_spectroscopy_amplifier.ino
new file mode 100644
index 0000000..0a3a888
--- /dev/null
+++ b/src/modules/puzzle_spectroscopy_amplifier/puzzle_spectroscopy_amplifier.ino
@@ -0,0 +1,76 @@
+// (c) 2022, redfast00
+// See the LICENSE file for conditions for copying
+
+#include
+
+// The shaping multiplier button has a bad contact when held down: wiggling the button will break/make contact
+// #define SHAPING_MULTIPLIER_PIN 10
+
+#define INPUT_POLARITY_PIN A2
+#define RESTORER_RATE_PIN A3
+#define RESTORER_MODE_PIN A4
+#define THRESHOLD_PIN A5
+#define PUR_PIN 9
+#define VAR_LED 5
+#define DISC_LED 6
+#define COARSE_GAIN_NETWORK_PIN A0
+#define SHAPING_TIME_NETWORK_PIN A1
+
+// Gets the position of a dial, given the pin connected to the resistor network
+uint8_t get_resistor_network_pin_index(uint8_t pin) {
+ int expected_values[6] = {0, 254, 407, 509, 582, 638};
+ int measured = analogRead(pin);
+ int minimal_difference = 1024;
+ uint8_t best_candidate = 0;
+ for (uint8_t i = 0; i < 6; i++) {
+ int difference = abs(measured - expected_values[i]);
+ if (difference < minimal_difference) {
+ minimal_difference = difference;
+ best_candidate = i;
+ }
+ }
+ return best_candidate;
+}
+
+void setup() {
+ Serial.begin(115200);
+ obus_module::setup(OBUS_TYPE_PUZZLE, 1);
+
+ // Switches and buttons
+ pinMode(INPUT_POLARITY_PIN, INPUT_PULLUP);
+ pinMode(RESTORER_RATE_PIN, INPUT_PULLUP);
+ pinMode(RESTORER_MODE_PIN, INPUT_PULLUP);
+ pinMode(THRESHOLD_PIN, INPUT_PULLUP);
+ pinMode(PUR_PIN, INPUT_PULLUP);
+
+ // LEDs
+ pinMode(VAR_LED, OUTPUT);
+ pinMode(DISC_LED, OUTPUT);
+
+ // resistor networks
+ pinMode(COARSE_GAIN_NETWORK_PIN, INPUT);
+ pinMode(SHAPING_TIME_NETWORK_PIN, INPUT);
+}
+
+
+
+obus_can::message message;
+
+void loop() {
+ obus_module::loopPuzzle(&message, callback_game_start, callback_game_stop);
+
+ // Some demo code to show everything works
+ bool var_value = digitalRead(INPUT_POLARITY_PIN) ^ digitalRead(RESTORER_MODE_PIN) ^ digitalRead(RESTORER_RATE_PIN) ^ digitalRead(THRESHOLD_PIN);
+ bool disc_value = (get_resistor_network_pin_index(COARSE_GAIN_NETWORK_PIN) % 2) ^ (get_resistor_network_pin_index(SHAPING_TIME_NETWORK_PIN) % 2) ^ digitalRead(PUR_PIN);
+ digitalWrite(VAR_LED, var_value);
+ digitalWrite(DISC_LED, disc_value);
+}
+
+void callback_game_start() {
+ // just instantly solve
+ obus_module::solve();
+}
+
+void callback_game_stop() {
+
+}