aboutsummaryrefslogtreecommitdiff
path: root/puzzle
diff options
context:
space:
mode:
Diffstat (limited to 'puzzle')
-rw-r--r--puzzle/dummy/CMakeLists.txt14
-rw-r--r--puzzle/dummy/FreeRTOSConfig.h4
-rw-r--r--puzzle/dummy/index.dox9
-rw-r--r--puzzle/dummy/makefile16
-rw-r--r--puzzle/neo/CMakeLists.txt44
-rw-r--r--puzzle/neo/FreeRTOSConfig.h52
-rw-r--r--puzzle/neo/console-neopuzzle/neo.cpp100
-rw-r--r--puzzle/neo/index.dox14
l---------puzzle/neo/lib1
-rw-r--r--puzzle/neo/main.cpp (renamed from puzzle/neo/arduino-neopuzzle/arduino-neopuzzle.ino)79
-rw-r--r--puzzle/neo/makefile8
-rw-r--r--puzzle/neo/mod.c6
-rw-r--r--puzzle/readme.md22
-rw-r--r--puzzle/vault/CMakeLists.txt41
-rw-r--r--puzzle/vault/FreeRTOSConfig.h52
-rw-r--r--puzzle/vault/arduino-vaultpuzzle/arduino-vaultpuzzle.ino150
-rw-r--r--puzzle/vault/console-vaultpuzzle/vault.cpp130
-rw-r--r--puzzle/vault/index.dox11
l---------puzzle/vault/lib1
-rw-r--r--puzzle/vault/main.cpp187
-rw-r--r--puzzle/vault/makefile8
-rw-r--r--puzzle/vault/mod.c6
22 files changed, 505 insertions, 450 deletions
diff --git a/puzzle/dummy/CMakeLists.txt b/puzzle/dummy/CMakeLists.txt
index 6acc4c8..7edce2b 100644
--- a/puzzle/dummy/CMakeLists.txt
+++ b/puzzle/dummy/CMakeLists.txt
@@ -11,14 +11,13 @@ add_compile_definitions(DEBUG)
# arduino
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/lib/Arduino-CMake-Toolchain/Arduino-toolchain.cmake)
-# set(ARDUINO_BOARD "Arduino Uno [avr.uno]")
-set(ARDUINO_BOARD "Arduino Mega or Mega 2560 [avr.mega]")
+set(ARDUINO_BOARD "Arduino Uno [avr.uno]")
+# set(ARDUINO_BOARD "Arduino Mega or Mega 2560 [avr.mega]")
-# freertos
+# freertos (used for memory management only)
add_library(freertos_config INTERFACE)
target_include_directories(freertos_config SYSTEM INTERFACE .)
-# set(FREERTOS_PORT GCC_ATMEGA) # Arduino Uno
-set(FREERTOS_PORT GCC_ATMEGA) # Arduino Uno
+set(FREERTOS_PORT GCC_ATMEGA)
set(FREERTOS_HEAP 4)
# used for testing
@@ -29,6 +28,7 @@ set(FREERTOS_HEAP 4)
project(pb_mod_dummy C CXX)
add_subdirectory(lib/pbdrv)
+include(lib/pbdrv/ext/freertos/include.cmake)
add_subdirectory(lib/FreeRTOS-Kernel)
add_executable(main
@@ -36,10 +36,10 @@ add_executable(main
mod.c
)
-target_link_libraries(main
+target_link_libraries(main PUBLIC
pbdrv-mod
)
-target_link_arduino_libraries(main
+target_link_arduino_libraries(main PUBLIC
core
Wire
)
diff --git a/puzzle/dummy/FreeRTOSConfig.h b/puzzle/dummy/FreeRTOSConfig.h
index 1cfdd71..1d98f78 100644
--- a/puzzle/dummy/FreeRTOSConfig.h
+++ b/puzzle/dummy/FreeRTOSConfig.h
@@ -17,8 +17,8 @@
#define configSTACK_DEPTH_TYPE uint16_t
#define configSUPPORT_STATIC_ALLOCATION 0
#define configSUPPORT_DYNAMIC_ALLOCATION 1
-// #define configTOTAL_HEAP_SIZE (1024)
-#define configTOTAL_HEAP_SIZE (7 * 1024)
+#define configTOTAL_HEAP_SIZE (1024)
+// #define configTOTAL_HEAP_SIZE (7 * 1024)
#define configCHECK_FOR_STACK_OVERFLOW 0
#define configUSE_MALLOC_FAILED_HOOK 0
#define configUSE_DAEMON_TASK_STARTUP_HOOK 0
diff --git a/puzzle/dummy/index.dox b/puzzle/dummy/index.dox
new file mode 100644
index 0000000..918bf7f
--- /dev/null
+++ b/puzzle/dummy/index.dox
@@ -0,0 +1,9 @@
+// vim:ft=doxygen
+/**
+\ingroup puz
+\defgroup puz_dummy Dummy
+\brief Demo puzzle module
+
+The dummy puzzle module consists of an empty Arduino sketch, and can be used as
+a starting point for developing new puzzle modules.
+*/
diff --git a/puzzle/dummy/makefile b/puzzle/dummy/makefile
index 509d8e3..6b8341b 100644
--- a/puzzle/dummy/makefile
+++ b/puzzle/dummy/makefile
@@ -3,18 +3,6 @@ TARGET = $(BUILD_DIR)/main.elf
include ../../lazy.mk
export SERIAL_PORT ?= /dev/ttyACM0
-flash: upload-main;
-upload-main: $(TARGET)
-
-test: test_a test_b;
-
-test_a:
- $(MAKE) -C . clean
- $(MAKE) -E CMFLAGS+=-D\ CMAKE_CXX_FLAGS=-DTEST_A -C .
- $(MAKE) -E SERIAL_PORT=/dev/ttyACM0 -C . flash
-
-test_b:
- $(MAKE) -C . clean
- $(MAKE) -E CMFLAGS+=-D\ CMAKE_CXX_FLAGS=-DTEST_B -C .
- $(MAKE) -E SERIAL_PORT=/dev/ttyACM1 -C . flash
+flash: upload;
+upload: $(TARGET)
diff --git a/puzzle/neo/CMakeLists.txt b/puzzle/neo/CMakeLists.txt
new file mode 100644
index 0000000..6c45f13
--- /dev/null
+++ b/puzzle/neo/CMakeLists.txt
@@ -0,0 +1,44 @@
+cmake_minimum_required(VERSION 3.29)
+
+set(CMAKE_C_STANDARD 11)
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
+
+# enable debug features
+set(CMAKE_BUILD_TYPE Debug)
+add_compile_definitions(DEBUG)
+
+# arduino
+set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/lib/Arduino-CMake-Toolchain/Arduino-toolchain.cmake)
+set(ARDUINO_BOARD "Arduino Mega or Mega 2560 [avr.mega]")
+
+# freertos
+add_library(freertos_config INTERFACE)
+target_include_directories(freertos_config SYSTEM INTERFACE .)
+set(FREERTOS_PORT GCC_ATMEGA)
+set(FREERTOS_HEAP 4)
+
+project(pb_mod_neo C CXX)
+
+add_subdirectory(lib/pbdrv)
+add_subdirectory(lib/FreeRTOS-Kernel)
+
+add_executable(main
+ main.cpp
+ mod.c
+ )
+
+target_link_libraries(main PUBLIC
+ pbdrv-mod
+ )
+target_link_arduino_libraries(main PUBLIC
+ core
+ Wire
+ Adafruit_seesaw
+ )
+
+# fugly workaround
+target_link_arduino_libraries(_arduino_lib_Adafruit_seesaw_Library PUBLIC "Adafruit BusIO")
+
+target_enable_arduino_upload(main)
+
diff --git a/puzzle/neo/FreeRTOSConfig.h b/puzzle/neo/FreeRTOSConfig.h
new file mode 100644
index 0000000..c0acc49
--- /dev/null
+++ b/puzzle/neo/FreeRTOSConfig.h
@@ -0,0 +1,52 @@
+#pragma once
+
+#define configUSE_PREEMPTION 1
+#define configUSE_IDLE_HOOK 0
+#define configUSE_TICK_HOOK 0
+#define configMAX_PRIORITIES 32
+#define configMINIMAL_STACK_SIZE ((configSTACK_DEPTH_TYPE) 192)
+#define configUSE_16_BIT_TICKS 1
+#define configIDLE_SHOULD_YIELD 1
+#define configUSE_MUTEXES 1
+#define configUSE_RECURSIVE_MUTEXES 1
+#define configUSE_APPLICATION_TASK_TAG 0
+#define configUSE_COUNTING_SEMAPHORES 1
+#define configQUEUE_REGISTRY_SIZE 8
+#define configUSE_QUEUE_SETS 0
+#define configUSE_TIME_SLICING 1
+#define configSTACK_DEPTH_TYPE uint16_t
+#define configSUPPORT_STATIC_ALLOCATION 0
+#define configSUPPORT_DYNAMIC_ALLOCATION 1
+// #define configTOTAL_HEAP_SIZE (1024)
+#define configTOTAL_HEAP_SIZE (5 * 1024)
+#define configCHECK_FOR_STACK_OVERFLOW 0
+#define configUSE_MALLOC_FAILED_HOOK 0
+#define configUSE_DAEMON_TASK_STARTUP_HOOK 0
+#define configGENERATE_RUN_TIME_STATS 0
+#define configUSE_TRACE_FACILITY 0
+#define configUSE_STATS_FORMATTING_FUNCTIONS 0
+#define configUSE_TIMERS 1
+#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1)
+#define configTIMER_QUEUE_LENGTH 10
+#define configTIMER_TASK_STACK_DEPTH 92
+
+#include <assert.h>
+#define configASSERT(x) assert(x)
+
+#define INCLUDE_vTaskPrioritySet 1
+#define INCLUDE_uxTaskPriorityGet 1
+#define INCLUDE_vTaskDelete 1
+#define INCLUDE_vTaskSuspend 1
+#define INCLUDE_vTaskDelayUntil 1
+#define INCLUDE_vTaskDelay 1
+#define INCLUDE_xTaskGetSchedulerState 1
+#define INCLUDE_xTaskGetCurrentTaskHandle 1
+#define INCLUDE_uxTaskGetStackHighWaterMark 1
+#define INCLUDE_xTaskGetIdleTaskHandle 1
+#define INCLUDE_eTaskGetState 1
+#define INCLUDE_xTimerPendFunctionCall 1
+#define INCLUDE_xTaskAbortDelay 1
+#define INCLUDE_xTaskGetHandle 1
+#define INCLUDE_xTaskResumeFromISR 1
+#define INCLUDE_xQueueGetMutexHolder 1
+
diff --git a/puzzle/neo/console-neopuzzle/neo.cpp b/puzzle/neo/console-neopuzzle/neo.cpp
deleted file mode 100644
index 56d90f7..0000000
--- a/puzzle/neo/console-neopuzzle/neo.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-#include <iostream>
-#include <array>
-
-#define MATRIX_SIZE 8
-
-enum NeoState {
- NEO_UNINITIALIZED,
- NEO_PLAYING,
- NEO_SOLVED
-};
-
-// Simulate the 8x8 LED matrix with a 2D array
-std::array<std::array<bool, MATRIX_SIZE>, MATRIX_SIZE> neoMatrix;
-
-NeoState neoState = NEO_UNINITIALIZED;
-
-// Helper function to toggle LEDs if within bounds
-void toggleIfValid(int x, int y) {
- if (x >= 0 && x < MATRIX_SIZE && y >= 0 && y < MATRIX_SIZE) {
- neoMatrix[x][y] = !neoMatrix[x][y];
- }
-}
-
-void initializeNeoMatrix() {
- // The initial pattern from the Appendix A example (assuming red is 'true'/on and white is 'false'/off)
- std::array<std::array<bool, MATRIX_SIZE>, MATRIX_SIZE> initialPattern = {{
- {false, true, false, true, false, true, false, true},
- {true, false, true, false, true, false, true, false},
- {false, true, false, true, false, true, false, true},
- {true, false, true, false, true, false, true, false},
- {false, true, false, true, false, true, false, true},
- {true, false, true, false, true, false, true, false},
- {false, true, false, true, false, true, false, true},
- {true, false, true, false, true, false, true, false}
- }};
-
- for (int i = 0; i < MATRIX_SIZE; i++) {
- for (int j = 0; j < MATRIX_SIZE; j++) {
- neoMatrix[i][j] = initialPattern[i][j];
- }
- }
-
- neoState = NEO_PLAYING;
-}
-
-
-void printNeoMatrix() {
- // Print the matrix state to the console
- for (int i = 0; i < MATRIX_SIZE; i++) {
- for (int j = 0; j < MATRIX_SIZE; j++) {
- std::cout << (neoMatrix[i][j] ? 1 : 0) << " ";
- }
- std::cout << std::endl;
- }
-}
-
-void toggleAdjacentLEDs(int x, int y) {
- // Toggle the LED at (x, y) and adjacent LEDs
- toggleIfValid(x, y); // Center
- toggleIfValid(x - 1, y); // Up
- toggleIfValid(x + 1, y); // Down
- toggleIfValid(x, y - 1); // Left
- toggleIfValid(x, y + 1); // Right
-}
-
-
-bool isNeoPuzzleSolved() {
- for (int i = 0; i < MATRIX_SIZE; i++) {
- for (int j = 0; j < MATRIX_SIZE; j++) {
- if (neoMatrix[i][j]) return false; // If any LED is on, puzzle is not solved
- }
- }
- return true;
-}
-
-/// Integration needed
-int main() {
- initializeNeoMatrix();
- printNeoMatrix();
-
- while (neoState != NEO_SOLVED) {
- int x, y;
- std::cout << "Enter the coordinates of the button pressed (x y): ";
- std::cin >> x >> y;
-
- if (x >= 0 && x < MATRIX_SIZE && y >= 0 && y < MATRIX_SIZE) {
- toggleAdjacentLEDs(x, y);
- printNeoMatrix();
-
- if (isNeoPuzzleSolved()) {
- neoState = NEO_SOLVED;
- std::cout << "The NeoTrellis puzzle is solved!\n";
- }
- } else {
- std::cout << "Invalid coordinates. Please enter values between 0 and " << MATRIX_SIZE - 1 << ".\n";
- }
- }
-
- return 0;
-}
diff --git a/puzzle/neo/index.dox b/puzzle/neo/index.dox
new file mode 100644
index 0000000..87822e0
--- /dev/null
+++ b/puzzle/neo/index.dox
@@ -0,0 +1,14 @@
+// vim:ft=doxygen
+/**
+\ingroup puz
+\defgroup puz_neo Neo
+\brief NeoTrellis puzzle module
+
+\par Setup
+- Use the Arduino IDE library manager to install the "Adafruit seesaw Library"
+ library and its dependencies
+
+\warning There is another library named "Adafruit NeoTrellis M4 Library", this
+is not the right library.
+
+*/
diff --git a/puzzle/neo/lib b/puzzle/neo/lib
new file mode 120000
index 0000000..58677dd
--- /dev/null
+++ b/puzzle/neo/lib
@@ -0,0 +1 @@
+../../lib \ No newline at end of file
diff --git a/puzzle/neo/arduino-neopuzzle/arduino-neopuzzle.ino b/puzzle/neo/main.cpp
index b334677..13a6859 100644
--- a/puzzle/neo/arduino-neopuzzle/arduino-neopuzzle.ino
+++ b/puzzle/neo/main.cpp
@@ -1,3 +1,4 @@
+#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_NeoTrellis.h>
@@ -22,6 +23,45 @@ enum NeoState {
NeoState neoState = NEO_UNINITIALIZED;
+void toggleAdjacentLEDs(int x, int y) {
+ for (int dx = -1; dx <= 1; ++dx) {
+ for (int dy = -1; dy <= 1; ++dy) {
+ if (dx == 0 && dy == 0) continue; // Skip the center button itself
+ int nx = x + dx, ny = y + dy;
+ if (nx >= 0 && nx < MATRIX_SIZE && ny >= 0 && ny < MATRIX_SIZE) {
+ neoMatrix[nx][ny] = !neoMatrix[nx][ny];
+ trellis.setPixelColor(nx * MATRIX_SIZE + ny, neoMatrix[nx][ny] ? LED_COLOR_ON : LED_COLOR_OFF);
+ }
+ }
+ }
+}
+
+
+bool isNeoPuzzleSolved() {
+ for (int i = 0; i < MATRIX_SIZE; i++) {
+ for (int j = 0; j < MATRIX_SIZE; j++) {
+ if (neoMatrix[i][j]) return false; // If any LED is on, puzzle is not solved
+ }
+ }
+ return true;
+}
+
+TrellisCallback buttonCallback(keyEvent evt) {
+ int x = evt.bit.NUM / MATRIX_SIZE;
+ int y = evt.bit.NUM % MATRIX_SIZE;
+
+ if (evt.bit.EDGE == SEESAW_KEYPAD_EDGE_RISING) {
+ toggleAdjacentLEDs(x, y);
+ trellis.show();
+ if (isNeoPuzzleSolved()) {
+ neoState = NEO_SOLVED;
+ Serial.println("The NeoTrellis puzzle is solved!");
+ }
+ }
+ return 0;
+}
+
+
void setup() {
Serial.begin(115200);
while (!Serial); // Wait for Serial to be ready
@@ -55,41 +95,4 @@ void setup() {
void loop() {
trellis.read(); // Process button events
delay(20);
-}
-
-TrellisCallback buttonCallback(keyEvent evt) {
- int x = evt.bit.NUM / MATRIX_SIZE;
- int y = evt.bit.NUM % MATRIX_SIZE;
-
- if (evt.bit.EDGE == SEESAW_KEYPAD_EDGE_RISING) {
- toggleAdjacentLEDs(x, y);
- trellis.show();
- if (isNeoPuzzleSolved()) {
- neoState = NEO_SOLVED;
- Serial.println("The NeoTrellis puzzle is solved!");
- }
- }
- return 0;
-}
-
-void toggleAdjacentLEDs(int x, int y) {
- for (int dx = -1; dx <= 1; ++dx) {
- for (int dy = -1; dy <= 1; ++dy) {
- if (dx == 0 && dy == 0) continue; // Skip the center button itself
- int nx = x + dx, ny = y + dy;
- if (nx >= 0 && nx < MATRIX_SIZE && ny >= 0 && ny < MATRIX_SIZE) {
- neoMatrix[nx][ny] = !neoMatrix[nx][ny];
- trellis.setPixelColor(nx * MATRIX_SIZE + ny, neoMatrix[nx][ny] ? LED_COLOR_ON : LED_COLOR_OFF);
- }
- }
- }
-}
-
-bool isNeoPuzzleSolved() {
- for (int i = 0; i < MATRIX_SIZE; i++) {
- for (int j = 0; j < MATRIX_SIZE; j++) {
- if (neoMatrix[i][j]) return false; // If any LED is on, puzzle is not solved
- }
- }
- return true;
-}
+} \ No newline at end of file
diff --git a/puzzle/neo/makefile b/puzzle/neo/makefile
new file mode 100644
index 0000000..26e9157
--- /dev/null
+++ b/puzzle/neo/makefile
@@ -0,0 +1,8 @@
+TARGET = $(BUILD_DIR)/main.elf
+
+include ../../lazy.mk
+
+export SERIAL_PORT ?= /dev/ttyACM0
+flash: upload-main;
+upload-main: $(TARGET)
+
diff --git a/puzzle/neo/mod.c b/puzzle/neo/mod.c
new file mode 100644
index 0000000..7157d22
--- /dev/null
+++ b/puzzle/neo/mod.c
@@ -0,0 +1,6 @@
+#include "pb.h"
+#include "pb-mod.h"
+
+const char * PB_MOD_NAME = "neotrellis";
+const i2c_addr_t PB_MOD_ADDR = PB_ADDR_MOD_NEOTRELLIS;
+
diff --git a/puzzle/readme.md b/puzzle/readme.md
index 59c10b1..1b572ba 100644
--- a/puzzle/readme.md
+++ b/puzzle/readme.md
@@ -1,15 +1,15 @@
-# puzzles
-
-This folder contains the source code for all puzzle modules.
+\defgroup puz puzzle
+\brief Puzzle modules
## Arduino-based puzzle modules
-Because of the poorly designed hardware (21-22) used during development
-(23-24), some puzzle modules ended up being developed using Arduino boards. All
-libraries in this repository use CMake for building (for consistency), which
-also means the Arduino based puzzle modules use CMake. The CMakeLists.txt of
-some puzzles uses the [Arduino-CMake-Toolchain][arduino-cmake]. To build any of
-these subfolders, make sure you have done the following:
+> [!NOTE]
+> Because of the poorly designed hardware (21-22) used during development
+> (23-24), all puzzle modules ended up being developed using Arduino boards.
+
+The Arduino based puzzle modules also use CMake with the
+[Arduino-CMake-Toolchain][arduino-cmake]. To build any of these puzzles, make
+sure you have done the following:
- Install the official Arduino IDE
- Open "Tools" > "Board" > "Board manager"
@@ -17,6 +17,8 @@ these subfolders, make sure you have done the following:
[arduino-cmake]: https://github.com/a9183756-gh/Arduino-CMake-Toolchain
+<!--
+
## ESP-based puzzle modules
### ESP-IDF SDK Setup instructions
@@ -29,3 +31,5 @@ these subfolders, make sure you have done the following:
- [For windows](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/get-started/windows-setup.html#get-started-windows-first-steps)
- [For Linux](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/get-started/linux-macos-setup.html#get-started-linux-macos-first-steps)
+-->
+
diff --git a/puzzle/vault/CMakeLists.txt b/puzzle/vault/CMakeLists.txt
new file mode 100644
index 0000000..bc13c8c
--- /dev/null
+++ b/puzzle/vault/CMakeLists.txt
@@ -0,0 +1,41 @@
+cmake_minimum_required(VERSION 3.29)
+
+set(CMAKE_C_STANDARD 11)
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
+
+# enable debug features
+set(CMAKE_BUILD_TYPE Debug)
+add_compile_definitions(DEBUG)
+
+# arduino
+set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/lib/Arduino-CMake-Toolchain/Arduino-toolchain.cmake)
+set(ARDUINO_BOARD "Arduino Mega or Mega 2560 [avr.mega]")
+
+# freertos
+add_library(freertos_config INTERFACE)
+target_include_directories(freertos_config SYSTEM INTERFACE .)
+set(FREERTOS_PORT GCC_ATMEGA)
+set(FREERTOS_HEAP 4)
+
+project(pb_mod_vault C CXX)
+
+add_subdirectory(lib/pbdrv)
+add_subdirectory(lib/FreeRTOS-Kernel)
+
+add_executable(main
+ main.cpp
+ mod.c
+ )
+
+target_link_libraries(main PUBLIC
+ pbdrv-mod
+ )
+target_link_arduino_libraries(main PUBLIC
+ core
+ Wire
+ TM1637
+ )
+
+target_enable_arduino_upload(main)
+
diff --git a/puzzle/vault/FreeRTOSConfig.h b/puzzle/vault/FreeRTOSConfig.h
new file mode 100644
index 0000000..c0acc49
--- /dev/null
+++ b/puzzle/vault/FreeRTOSConfig.h
@@ -0,0 +1,52 @@
+#pragma once
+
+#define configUSE_PREEMPTION 1
+#define configUSE_IDLE_HOOK 0
+#define configUSE_TICK_HOOK 0
+#define configMAX_PRIORITIES 32
+#define configMINIMAL_STACK_SIZE ((configSTACK_DEPTH_TYPE) 192)
+#define configUSE_16_BIT_TICKS 1
+#define configIDLE_SHOULD_YIELD 1
+#define configUSE_MUTEXES 1
+#define configUSE_RECURSIVE_MUTEXES 1
+#define configUSE_APPLICATION_TASK_TAG 0
+#define configUSE_COUNTING_SEMAPHORES 1
+#define configQUEUE_REGISTRY_SIZE 8
+#define configUSE_QUEUE_SETS 0
+#define configUSE_TIME_SLICING 1
+#define configSTACK_DEPTH_TYPE uint16_t
+#define configSUPPORT_STATIC_ALLOCATION 0
+#define configSUPPORT_DYNAMIC_ALLOCATION 1
+// #define configTOTAL_HEAP_SIZE (1024)
+#define configTOTAL_HEAP_SIZE (5 * 1024)
+#define configCHECK_FOR_STACK_OVERFLOW 0
+#define configUSE_MALLOC_FAILED_HOOK 0
+#define configUSE_DAEMON_TASK_STARTUP_HOOK 0
+#define configGENERATE_RUN_TIME_STATS 0
+#define configUSE_TRACE_FACILITY 0
+#define configUSE_STATS_FORMATTING_FUNCTIONS 0
+#define configUSE_TIMERS 1
+#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1)
+#define configTIMER_QUEUE_LENGTH 10
+#define configTIMER_TASK_STACK_DEPTH 92
+
+#include <assert.h>
+#define configASSERT(x) assert(x)
+
+#define INCLUDE_vTaskPrioritySet 1
+#define INCLUDE_uxTaskPriorityGet 1
+#define INCLUDE_vTaskDelete 1
+#define INCLUDE_vTaskSuspend 1
+#define INCLUDE_vTaskDelayUntil 1
+#define INCLUDE_vTaskDelay 1
+#define INCLUDE_xTaskGetSchedulerState 1
+#define INCLUDE_xTaskGetCurrentTaskHandle 1
+#define INCLUDE_uxTaskGetStackHighWaterMark 1
+#define INCLUDE_xTaskGetIdleTaskHandle 1
+#define INCLUDE_eTaskGetState 1
+#define INCLUDE_xTimerPendFunctionCall 1
+#define INCLUDE_xTaskAbortDelay 1
+#define INCLUDE_xTaskGetHandle 1
+#define INCLUDE_xTaskResumeFromISR 1
+#define INCLUDE_xQueueGetMutexHolder 1
+
diff --git a/puzzle/vault/arduino-vaultpuzzle/arduino-vaultpuzzle.ino b/puzzle/vault/arduino-vaultpuzzle/arduino-vaultpuzzle.ino
deleted file mode 100644
index 4dd8ac8..0000000
--- a/puzzle/vault/arduino-vaultpuzzle/arduino-vaultpuzzle.ino
+++ /dev/null
@@ -1,150 +0,0 @@
-#include <Wire.h>
-#include <TM1637Display.h>
-
-// Definitions for GPIO numbers, change these according to your hardware setup
-#define TOTAL_LEVELS 5
-#define TAG "VaultPuzzle"
-
-// Key Matrix Pin Configuration
-#define ROWS 4
-#define COLS 3
-
-// Module connection pins (Digital Pins for TM1637)
-#define CLK 2
-#define DIO 3
-
-// Pin to indicate puzzle solved state
-#define SOLVED_PIN 53
-
-// Initialize the TM1637 display
-TM1637Display display(CLK, DIO);
-
-//TODO Update these pin numbers based on your Arduino setup
-const int ROW_PINS[ROWS] = {7, 6, 5, 4};
-const int COL_PINS[COLS] = {10, 9, 8};
-
-typedef enum {
- STATE_UNINITIALIZED = 0x00,
- STATE_RESET = 0x01,
- STATE_PLAYING = 0x02,
- STATE_SOLVED = 0x03,
- STATE_ERROR = 0x04
-} PuzzleState;
-
-const char* validButtons[TOTAL_LEVELS] = {"A2", "B1", "D3", "C2", "C1"};
-PuzzleState puzzleState = STATE_UNINITIALIZED;
-int currentLevel = 0;
-
-// Function prototypes
-void display_code(int level);
-void initialize_system();
-void check_button_press();
-void update_state_after_button_press(bool validPress);
-void play_error_sound();
-void blink_display();
-
-void setup() {
- Serial.begin(115200); // Initialize default Serial for debug messages
- pinMode(SOLVED_PIN, OUTPUT); // Initialize the solved indicator pin
- digitalWrite(SOLVED_PIN, LOW); // Start with the solved pin LOW
-
- display.setBrightness(0x0f); // Set the brightness of the TM1637 display
- initialize_system();
- Serial.println("GPIO and display initialized.");
-
- // Test to light up all segments
- uint8_t allOn[] = {0xFF, 0xFF, 0xFF, 0xFF}; // All segments on
- display.setSegments(allOn);
- delay(2000); // Keep it on for 2 seconds before proceeding
-
- // Initialize the game
- if (true) { // Simulating isVaultClosed
- puzzleState = STATE_RESET;
- currentLevel = 0;
- display_code(currentLevel);
- } else {
- Serial.println("Vault door is open. Please close the door to start the puzzle.");
- }
-}
-
-void initialize_system() {
- // Configure the rows as input with pull-up
- for (int i = 0; i < ROWS; i++) {
- pinMode(ROW_PINS[i], INPUT_PULLUP);
- }
-
- // Configure the columns as output
- for (int i = 0; i < COLS; i++) {
- pinMode(COL_PINS[i], OUTPUT);
- digitalWrite(COL_PINS[i], HIGH);
- }
-}
-
-void loop() {
- while (puzzleState != STATE_SOLVED) {
- check_button_press();
- delay(100); // Non-blocking delay
- }
- // When puzzle is solved, you might want to display a final message and set the solved pin high
- if (puzzleState == STATE_SOLVED) {
- digitalWrite(SOLVED_PIN, HIGH); // Set the solved pin high
- display.showNumberDec(currentLevel, true); // Show final level or a special message
- Serial.println("Final display shown. Puzzle complete.");
- while (1) { delay(1000); } // Hold on the final display
- }
-}
-
-void display_code(int level) {
- Serial.print("Displaying code for level "); Serial.println(level);
- // Display the level on the TM1637 4-digit 7-segment display
- display.showNumberDec(level, true); // True to show leading zeros
- Serial.print("Code for level "); Serial.print(level); Serial.println(" displayed successfully.");
-}
-
-void check_button_press() {
- char keyPress[3] = {0};
- for (int col = 0; col < COLS; col++) {
- digitalWrite(COL_PINS[col], LOW); // Activate column
- for (int row = 0; row < ROWS; row++) {
- if (digitalRead(ROW_PINS[row]) == LOW) { // Detect if any row is activated
- delay(50); // Debounce delay
- if (digitalRead(ROW_PINS[row]) == LOW) { // Confirm the button is still pressed
- keyPress[0] = 'A' + row;
- keyPress[1] = '1' + col;
- keyPress[2] = '\0';
- Serial.print("Keypress detected: "); Serial.println(keyPress);
- if (strcmp(keyPress, validButtons[currentLevel]) == 0) {
- currentLevel++;
- if (currentLevel >= TOTAL_LEVELS) {
- puzzleState = STATE_SOLVED;
- Serial.println("Puzzle solved!");
- display.showNumberDec(currentLevel + 1, true); // Display the final level
- digitalWrite(SOLVED_PIN, HIGH); // Set the solved pin high
- } else {
- puzzleState = STATE_PLAYING;
- display_code(currentLevel);
- }
- } else {
- play_error_sound();
- blink_display();
- puzzleState = STATE_ERROR;
- currentLevel = 0;
- display_code(currentLevel);
- }
- while (digitalRead(ROW_PINS[row]) == LOW) {} // Wait for release
- }
- }
- }
- digitalWrite(COL_PINS[col], HIGH); // Deactivate column
- }
-}
-
-void play_error_sound() {
- // Simulate error sound - connect a buzzer to play actual sound
- Serial.println("Playing error sound.");
-}
-
-void blink_display() {
- // Simulate blinking the display - use LEDs or other methods to show visual feedback
- Serial.println("7-segment display is blinking to indicate an error.");
-}
diff --git a/puzzle/vault/console-vaultpuzzle/vault.cpp b/puzzle/vault/console-vaultpuzzle/vault.cpp
deleted file mode 100644
index 3566b3e..0000000
--- a/puzzle/vault/console-vaultpuzzle/vault.cpp
+++ /dev/null
@@ -1,130 +0,0 @@
-#include <iostream>
-#include <string>
-#include <array>
-
-// Definitions for puzzle requirements
-constexpr int TOTAL_LEVELS = 5;
-
-// Enumeration for the states of the puzzle
-enum PuzzleState {
- STATE_UNINITIALIZED,
- STATE_RESET,
- STATE_PLAYING,
- STATE_SOLVED,
- STATE_ERROR
-};
-
-// This array maps each level to the correct button press
-const std::array<std::string, TOTAL_LEVELS> validButtons = {"A3", "F1", "U4", "C2", "L1"};
-
-PuzzleState puzzleState = STATE_UNINITIALIZED;
-int currentLevel = 0;
-
-// Function prototypes
-void displayCode(int level);
-void sendI2CUpdate(PuzzleState state);
-
-// Simulate sending an I2C update
-void sendI2CUpdate(PuzzleState state) {
- std::cout << "Sending state " << state << " to main controller via I2C.\n";
-}
-
-// Simulate checking if the vault door is closed
-bool isVaultClosed() {
- return true; // Return true if the door sensor indicates closed
-}
-
-// Function to display a code on the 7-segment display
-void displayCode(int level) {
- std::cout << "Displaying code for level " << level << " on the 7-segment display.\n";
-}
-
-// Function to initialize the puzzle
-void initializePuzzle() {
- if (isVaultClosed()) {
- puzzleState = STATE_RESET;
- currentLevel = 1; // Start at level 1
- std::cout << "Puzzle initialized. Starting at level " << currentLevel << ".\n";
- displayCode(currentLevel); // Show the first code
- } else {
- std::cout << "Vault door is open. Please close the door to start the puzzle.\n";
- }
-}
-
-// Function to lock the vault
-void lockVault() {
- std::cout << "Vault locked.\n";
-}
-
-// Function to unlock the vault
-void unlockVault() {
- std::cout << "Vault unlocked!\n";
-}
-
-// Function to simulate the buzzer sound
-void playErrorSound() {
- std::cout << "Playing error sound.\n";
-}
-
-// Function to simulate blinking the 7-segment display
-void blinkDisplay() {
- std::cout << "7-segment display is blinking to indicate an error.\n";
-}
-
-// Validate the button press for the current level
-bool isValidButtonPress(const std::string& button, int level) {
- return button == validButtons[level - 1];
-}
-
-// Function to update the state of the puzzle based on the current level
-void updateStateAfterButtonPress(bool validPress) {
- if (validPress) {
- if (currentLevel >= TOTAL_LEVELS) {
- puzzleState = STATE_SOLVED;
- unlockVault();
- } else {
- puzzleState = STATE_PLAYING;
- displayCode(currentLevel);
- }
- } else {
- puzzleState = STATE_ERROR;
- playErrorSound();
- blinkDisplay();
- lockVault();
- currentLevel = 1; // Reset to level 1
- displayCode(currentLevel);
- }
- sendI2CUpdate(puzzleState); // Notify main controller of the state change
-}
-
-int main() {
- initializePuzzle();
-
- std::string buttonInput;
-
- while (puzzleState != STATE_SOLVED) {
- std::cout << "Enter the button pressed for level " << currentLevel << " (format Xn, e.g., A3): ";
- std::getline(std::cin, buttonInput);
-
- if (!buttonInput.empty() && isValidButtonPress(buttonInput, currentLevel)) {
- currentLevel++;
- if (currentLevel > TOTAL_LEVELS) {
- puzzleState = STATE_SOLVED;
- unlockVault();
- std::cout << "The puzzle is solved and the vault is open!\n";
- } else {
- displayCode(currentLevel);
- }
- } else {
- playErrorSound();
- blinkDisplay();
- lockVault();
- puzzleState = STATE_RESET;
- currentLevel = 1;
- displayCode(currentLevel);
- }
- sendI2CUpdate(puzzleState);
- }
-
- return 0;
-}
diff --git a/puzzle/vault/index.dox b/puzzle/vault/index.dox
new file mode 100644
index 0000000..15eae1f
--- /dev/null
+++ b/puzzle/vault/index.dox
@@ -0,0 +1,11 @@
+// vim:ft=doxygen
+/**
+\ingroup puz
+\defgroup puz_vault Vault
+\brief Vault puzzle module
+
+\par Setup
+- Use the Arduino IDE library manager to install the "TM1637" library (by
+ Avishay Orpaz) and its dependencies
+
+*/
diff --git a/puzzle/vault/lib b/puzzle/vault/lib
new file mode 120000
index 0000000..58677dd
--- /dev/null
+++ b/puzzle/vault/lib
@@ -0,0 +1 @@
+../../lib \ No newline at end of file
diff --git a/puzzle/vault/main.cpp b/puzzle/vault/main.cpp
new file mode 100644
index 0000000..2e4cafc
--- /dev/null
+++ b/puzzle/vault/main.cpp
@@ -0,0 +1,187 @@
+#include <Arduino.h>
+#include <TM1637Display.h>
+#include "lib/pbdrv/pb-types.h"
+#include "lib/pbdrv/pb-mod.h"
+
+#define TOTAL_LEVELS 5
+#define ROWS 4
+#define COLS 3
+#define CLK 2
+#define DIO 3
+#define SOLVED_PIN 53
+#define I2C_MODULE_ADDRESS 0x08 // Address of the puzzle module
+#define HANDSHAKE_RECEIVED {0x70, 0x75, 0x7a, 0x62, 0x75, 0x73} // Magic command for the handshake
+#define HANDSHAKE_SEND {0x67, 0x61, 0x6d, 0x69, 0x6e, 0x67} // Magic command for the handshake
+#define REQUEST_STATE_CMD 0x53 // 'S' to request the game state
+
+const int ROW_PINS[ROWS] = {7, 6, 5, 4};
+const int COL_PINS[COLS] = {10, 9, 8};
+const char* validButtons[TOTAL_LEVELS] = {"A2", "B1", "D3", "C2", "C3"};
+const char bombCode[] = "1234";
+const uint8_t SEGMENT_MAP[] = {
+ 0b00111111, // 0
+ 0b00000110, // 1
+ 0b01011011, // 2
+ 0b01001111, // 3
+ 0b01100110, // 4
+ 0b01101101, // 5
+ 0b01111101, // 6
+ 0b00000111, // 7
+ 0b01111111, // 8
+ 0b01101111, // 9
+ 0b01110111, // A
+ 0b01111100, // B
+ 0b00111001, // C
+ 0b01011110, // D
+ 0b01111001, // E
+ 0b01110001 // F
+ // Add other letters if needed
+};
+
+// This array of level codes matches the codes you might display per level.
+const char* levelCodes[TOTAL_LEVELS] = {"A1", "B2", "D1", "C3", "A2"};
+
+
+// Puzzle state
+pb_global_state_t puzzleState = PB_GS_NOINIT;
+
+TM1637Display display(CLK, DIO);
+
+int currentLevel = 0;
+
+void blink_display(int num) {
+ if (num == 1) {
+ // Display "1111" with leading zeros shown if necessary
+ display.showNumberDecEx(1111, 0b11111111, true);
+ } else if (num == 0) {
+ // Display "0000" with leading zeros shown if necessary
+ display.showNumberDecEx(0, 0b11111111, true);
+ }
+ delay(500);
+ display.clear();
+ delay(500);
+}
+
+
+void display_final_code(const char* code) {
+ uint8_t segs[4] = {0, 0, 0, 0};
+ int numDigits = strlen(code);
+ numDigits = numDigits > 4 ? 4 : numDigits;
+
+ for (int i = 0; i < numDigits; i++) {
+ segs[i] = display.encodeDigit(code[i] - '0');
+ }
+
+ display.setSegments(segs, numDigits, 0);
+}
+
+void check_button_press() {
+ for (int col = 0; col < COLS; col++) {
+ digitalWrite(COL_PINS[col], LOW);
+ for (int row = 0; row < ROWS; row++) {
+ if (digitalRead(ROW_PINS[row]) == LOW) {
+ delay(50);
+ if (digitalRead(ROW_PINS[row]) == LOW) {
+ char keyPress[3] = {'A' + row, '1' + col, '\0'};
+ Serial.print("Keypress detected: ");
+ Serial.println(keyPress);
+ if (strcmp(keyPress, validButtons[currentLevel]) == 0) {
+ currentLevel++;
+ if (currentLevel >= TOTAL_LEVELS) {
+ pb_hook_mod_state_write(PB_GS_SOLVED);
+ Serial.println("Puzzle solved!");
+ display.showNumberDec(currentLevel + 1, true);
+ digitalWrite(SOLVED_PIN, HIGH);
+ }
+ } else {
+ currentLevel = 0;
+ }
+ while (digitalRead(ROW_PINS[row]) == LOW) {} // Ensure button release
+ }
+ }
+ }
+ digitalWrite(COL_PINS[col], HIGH);
+ }
+}
+
+void initialize_system() {
+ for (int i = 0; i < ROWS; i++) {
+ pinMode(ROW_PINS[i], INPUT_PULLUP);
+ }
+ for (int i = 0; i < COLS; i++) {
+ pinMode(COL_PINS[i], OUTPUT);
+ digitalWrite(COL_PINS[i], HIGH);
+ }
+ Serial.println("GPIO and display initialized.");
+}
+
+void display_code_for_level(int level) {
+ char code[3] = {0}; // Temp storage for level code
+ strncpy(code, levelCodes[level], 2); // Copy the level-specific code
+
+ uint8_t segs[4] = {0}; // Segments to send to the display
+
+ // Check if the first character is a letter and map it
+ if (isalpha(code[0])) {
+ if (code[0] >= 'A' && code[0] <= 'F') {
+ segs[0] = SEGMENT_MAP[code[0] - 'A' + 10]; // Maps A-F to their segment patterns
+ } else {
+ // Handle unexpected characters or extend SEGMENT_MAP for more letters
+ segs[0] = 0; // Display nothing for undefined letters
+ }
+ } else {
+ // Assume it's a number and map directly
+ segs[0] = SEGMENT_MAP[code[0] - '0'];
+ }
+
+ // Check if the second character is a digit and map it
+ if (isdigit(code[1])) {
+ segs[1] = SEGMENT_MAP[code[1] - '0'];
+ } else {
+ // Handle unexpected characters
+ segs[1] = 0; // Display nothing for undefined digits
+ }
+
+ // Set only the first two segments, leave others blank
+ display.setSegments(segs, 2, 0); // Display on leftmost two digits
+}
+
+
+pb_global_state_t pb_hook_mod_state_read() {
+ return puzzleState;
+}
+
+void pb_hook_mod_state_write(pb_global_state_t state) {
+ puzzleState = state;
+}
+
+void setup() {
+ Serial.begin(115200);
+ pinMode(SOLVED_PIN, OUTPUT);
+ digitalWrite(SOLVED_PIN, LOW);
+ display.setBrightness(0x0f);
+ initialize_system();
+}
+
+void loop() {
+ switch(puzzleState) {
+ case PB_GS_PLAYING:
+ display_code_for_level(currentLevel);
+ check_button_press();
+ delay(100);
+ break;
+ case PB_GS_SOLVED:
+ Serial.println("STATE = PB_GS_SOLVED");
+ display_final_code(bombCode);
+ digitalWrite(SOLVED_PIN, HIGH);
+ break;
+ case PB_GS_NOINIT:
+ Serial.println("STATE = PB_GS_NOINIT");
+ blink_display(0);
+ break;
+ case PB_GS_IDLE:
+ Serial.println("STATE = PB_GS_IDLE");
+ blink_display(1);
+ break;
+ }
+} \ No newline at end of file
diff --git a/puzzle/vault/makefile b/puzzle/vault/makefile
new file mode 100644
index 0000000..f33ca7e
--- /dev/null
+++ b/puzzle/vault/makefile
@@ -0,0 +1,8 @@
+TARGET = $(BUILD_DIR)/main.elf
+
+include ../../lazy.mk
+
+export SERIAL_PORT ?= /dev/ttyUSB0
+flash: upload;
+upload: $(TARGET)
+
diff --git a/puzzle/vault/mod.c b/puzzle/vault/mod.c
new file mode 100644
index 0000000..bae8a3d
--- /dev/null
+++ b/puzzle/vault/mod.c
@@ -0,0 +1,6 @@
+#include "pb.h"
+#include "pb-mod.h"
+
+const char * PB_MOD_NAME = "vault";
+const i2c_addr_t PB_MOD_ADDR = PB_ADDR_MOD_VAULT;
+