aboutsummaryrefslogtreecommitdiff
path: root/main/puzzle/neo/esp-neopuzzle
diff options
context:
space:
mode:
authorElwin Hammer <elwinhamer@gmail.com>2024-04-23 11:49:54 +0200
committerElwin Hammer <elwinhamer@gmail.com>2024-04-23 11:49:54 +0200
commit65f139edb2d3cfa055504e04cba266566fdfbf3b (patch)
treed0c19ceec58bb1df5ee03aa09b861b2bbbe5df31 /main/puzzle/neo/esp-neopuzzle
parent7b8d066223b9af513193020423b86c9f52234001 (diff)
ESP version of the neotrellis puzzle (first setup)
Diffstat (limited to 'main/puzzle/neo/esp-neopuzzle')
-rw-r--r--main/puzzle/neo/esp-neopuzzle/.devcontainer/Dockerfile47
-rw-r--r--main/puzzle/neo/esp-neopuzzle/.devcontainer/devcontainer.json45
-rw-r--r--main/puzzle/neo/esp-neopuzzle/.vscode/c_cpp_properties.json27
-rw-r--r--main/puzzle/neo/esp-neopuzzle/.vscode/launch.json10
-rw-r--r--main/puzzle/neo/esp-neopuzzle/.vscode/settings.json17
-rw-r--r--main/puzzle/neo/esp-neopuzzle/.vscode/tasks.json259
-rw-r--r--main/puzzle/neo/esp-neopuzzle/CMakeLists.txt8
-rw-r--r--main/puzzle/neo/esp-neopuzzle/README.md35
-rw-r--r--main/puzzle/neo/esp-neopuzzle/main/CMakeLists.txt2
-rw-r--r--main/puzzle/neo/esp-neopuzzle/main/main.c85
10 files changed, 535 insertions, 0 deletions
diff --git a/main/puzzle/neo/esp-neopuzzle/.devcontainer/Dockerfile b/main/puzzle/neo/esp-neopuzzle/.devcontainer/Dockerfile
new file mode 100644
index 0000000..1fe78dc
--- /dev/null
+++ b/main/puzzle/neo/esp-neopuzzle/.devcontainer/Dockerfile
@@ -0,0 +1,47 @@
+FROM espressif/idf
+
+ARG DEBIAN_FRONTEND=nointeractive
+ARG CONTAINER_USER=esp
+ARG USER_UID=1000
+ARG USER_GID=$USER_UID
+
+RUN apt-get update \
+ && apt install -y -q \
+ cmake \
+ git \
+ libglib2.0-0 \
+ libnuma1 \
+ libpixman-1-0 \
+ && rm -rf /var/lib/apt/lists/*
+
+# QEMU
+ENV QEMU_REL=esp_develop_8.2.0_20240122
+ENV QEMU_SHA256=e7c72ef5705ad1444d391711088c8717fc89f42e9bf6d1487f9c2a326b8cfa83
+ENV QEMU_DIST=qemu-xtensa-softmmu-${QEMU_REL}-x86_64-linux-gnu.tar.xz
+ENV QEMU_URL=https://github.com/espressif/qemu/releases/download/esp-develop-8.2.0-20240122/${QEMU_DIST}
+
+ENV LC_ALL=C.UTF-8
+ENV LANG=C.UTF-8
+
+RUN wget --no-verbose ${QEMU_URL} \
+ && echo "${QEMU_SHA256} *${QEMU_DIST}" | sha256sum --check --strict - \
+ && tar -xf $QEMU_DIST -C /opt \
+ && rm ${QEMU_DIST}
+
+ENV PATH=/opt/qemu/bin:${PATH}
+
+RUN groupadd --gid $USER_GID $CONTAINER_USER \
+ && adduser --uid $USER_UID --gid $USER_GID --disabled-password --gecos "" ${CONTAINER_USER} \
+ && usermod -a -G root $CONTAINER_USER && usermod -a -G dialout $CONTAINER_USER
+
+RUN chmod -R 775 /opt/esp/python_env/
+
+USER ${CONTAINER_USER}
+ENV USER=${CONTAINER_USER}
+WORKDIR /home/${CONTAINER_USER}
+
+RUN echo "source /opt/esp/idf/export.sh > /dev/null 2>&1" >> ~/.bashrc
+
+ENTRYPOINT [ "/opt/esp/entrypoint.sh" ]
+
+CMD ["/bin/bash", "-c"] \ No newline at end of file
diff --git a/main/puzzle/neo/esp-neopuzzle/.devcontainer/devcontainer.json b/main/puzzle/neo/esp-neopuzzle/.devcontainer/devcontainer.json
new file mode 100644
index 0000000..1d913ec
--- /dev/null
+++ b/main/puzzle/neo/esp-neopuzzle/.devcontainer/devcontainer.json
@@ -0,0 +1,45 @@
+// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
+// https://github.com/microsoft/vscode-dev-containers/tree/v0.183.0/containers/ubuntu
+{
+ "name": "ESP-IDF QEMU",
+ "build": {
+ "dockerfile": "Dockerfile"
+ },
+ // Add the IDs of extensions you want installed when the container is created
+ "workspaceMount": "source=${localWorkspaceFolder},target=${localWorkspaceFolder},type=bind",
+ /* the path of workspace folder to be opened after container is running
+ */
+ "workspaceFolder": "${localWorkspaceFolder}",
+ "mounts": [
+ "source=extensionCache,target=/root/.vscode-server/extensions,type=volume"
+ ],
+ "customizations": {
+ "vscode": {
+ "settings": {
+ "terminal.integrated.defaultProfile.linux": "bash",
+ "idf.espIdfPath": "/opt/esp/idf",
+ "idf.customExtraPaths": "",
+ "idf.pythonBinPath": "/opt/esp/python_env/idf5.3_py3.10_env/bin/python",
+ "idf.toolsPath": "/opt/esp",
+ "idf.gitPath": "/usr/bin/git"
+ },
+ "extensions": [
+ "espressif.esp-idf-extension"
+ ],
+ },
+ "codespaces": {
+ "settings": {
+ "terminal.integrated.defaultProfile.linux": "bash",
+ "idf.espIdfPath": "/opt/esp/idf",
+ "idf.customExtraPaths": "",
+ "idf.pythonBinPath": "/opt/esp/python_env/idf5.3_py3.10_env/bin/python",
+ "idf.toolsPath": "/opt/esp",
+ "idf.gitPath": "/usr/bin/git"
+ },
+ "extensions": [
+ "espressif.esp-idf-extension"
+ ],
+ }
+ },
+ "runArgs": ["--privileged"]
+} \ No newline at end of file
diff --git a/main/puzzle/neo/esp-neopuzzle/.vscode/c_cpp_properties.json b/main/puzzle/neo/esp-neopuzzle/.vscode/c_cpp_properties.json
new file mode 100644
index 0000000..ee1cac1
--- /dev/null
+++ b/main/puzzle/neo/esp-neopuzzle/.vscode/c_cpp_properties.json
@@ -0,0 +1,27 @@
+{
+ "configurations": [
+ {
+ "name": "ESP-IDF",
+ "compilerPath": "${config:idf.toolsPathWin}\\tools\\xtensa-esp-elf\\esp-13.2.0_20230928\\xtensa-esp-elf\\bin\\xtensa-esp32-elf-gcc.exe",
+ "compileCommands": "${workspaceFolder}/build/compile_commands.json",
+ "includePath": [
+ "${config:idf.espIdfPath}/components/**",
+ "${config:idf.espIdfPathWin}/components/**",
+ "${config:idf.espAdfPath}/components/**",
+ "${config:idf.espAdfPathWin}/components/**",
+ "${workspaceFolder}/**"
+ ],
+ "browse": {
+ "path": [
+ "${config:idf.espIdfPath}/components",
+ "${config:idf.espIdfPathWin}/components",
+ "${config:idf.espAdfPath}/components/**",
+ "${config:idf.espAdfPathWin}/components/**",
+ "${workspaceFolder}"
+ ],
+ "limitSymbolsToIncludedHeaders": false
+ }
+ }
+ ],
+ "version": 4
+}
diff --git a/main/puzzle/neo/esp-neopuzzle/.vscode/launch.json b/main/puzzle/neo/esp-neopuzzle/.vscode/launch.json
new file mode 100644
index 0000000..6d2236f
--- /dev/null
+++ b/main/puzzle/neo/esp-neopuzzle/.vscode/launch.json
@@ -0,0 +1,10 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "type": "espidf",
+ "name": "Launch",
+ "request": "launch"
+ }
+ ]
+} \ No newline at end of file
diff --git a/main/puzzle/neo/esp-neopuzzle/.vscode/settings.json b/main/puzzle/neo/esp-neopuzzle/.vscode/settings.json
new file mode 100644
index 0000000..49f00b0
--- /dev/null
+++ b/main/puzzle/neo/esp-neopuzzle/.vscode/settings.json
@@ -0,0 +1,17 @@
+{
+ "C_Cpp.intelliSenseEngine": "default",
+ "idf.adapterTargetName": "esp32",
+ "idf.customExtraPaths": "C:\\Users\\Elwin\\.espressif\\tools\\xtensa-esp-elf-gdb\\12.1_20231023\\xtensa-esp-elf-gdb\\bin;C:\\Users\\Elwin\\.espressif\\tools\\riscv32-esp-elf-gdb\\12.1_20231023\\riscv32-esp-elf-gdb\\bin;C:\\Users\\Elwin\\.espressif\\tools\\xtensa-esp-elf\\esp-13.2.0_20230928\\xtensa-esp-elf\\bin;C:\\Users\\Elwin\\.espressif\\tools\\riscv32-esp-elf\\esp-13.2.0_20230928\\riscv32-esp-elf\\bin;C:\\Users\\Elwin\\.espressif\\tools\\esp32ulp-elf\\2.35_20220830\\esp32ulp-elf\\bin;C:\\Users\\Elwin\\.espressif\\tools\\cmake\\3.24.0\\bin;C:\\Users\\Elwin\\.espressif\\tools\\openocd-esp32\\v0.12.0-esp32-20230921\\openocd-esp32\\bin;C:\\Users\\Elwin\\.espressif\\tools\\ninja\\1.11.1;C:\\Users\\Elwin\\.espressif\\tools\\idf-exe\\1.0.3;C:\\Users\\Elwin\\.espressif\\tools\\ccache\\4.8\\ccache-4.8-windows-x86_64;C:\\Users\\Elwin\\.espressif\\tools\\dfu-util\\0.11\\dfu-util-0.11-win64;C:\\Users\\Elwin\\.espressif\\tools\\esp-rom-elfs\\20230320",
+ "idf.customExtraVars": {
+ "OPENOCD_SCRIPTS": "C:\\Users\\Elwin\\.espressif\\tools\\openocd-esp32\\v0.12.0-esp32-20230921/openocd-esp32/share/openocd/scripts",
+ "IDF_CCACHE_ENABLE": "1",
+ "ESP_ROM_ELF_DIR": "C:\\Users\\Elwin\\.espressif\\tools\\esp-rom-elfs\\20230320/"
+ },
+ "idf.espIdfPathWin": "C:\\Users\\Elwin\\esp\\v5.2.1\\esp-idf",
+ "idf.openOcdConfigs": [
+ "interface/ftdi/esp32_devkitj_v1.cfg",
+ "target/esp32.cfg"
+ ],
+ "idf.pythonBinPathWin": "C:\\Users\\Elwin\\.espressif\\python_env\\idf5.2_py3.11_env\\Scripts\\python.exe",
+ "idf.toolsPathWin": "C:\\Users\\Elwin\\.espressif"
+}
diff --git a/main/puzzle/neo/esp-neopuzzle/.vscode/tasks.json b/main/puzzle/neo/esp-neopuzzle/.vscode/tasks.json
new file mode 100644
index 0000000..1dc7915
--- /dev/null
+++ b/main/puzzle/neo/esp-neopuzzle/.vscode/tasks.json
@@ -0,0 +1,259 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "Build - Build project",
+ "type": "shell",
+ "command": "${config:idf.pythonBinPath} ${config:idf.espIdfPath}/tools/idf.py build",
+ "windows": {
+ "command": "${config:idf.pythonBinPathWin} ${config:idf.espIdfPathWin}\\tools\\idf.py build",
+ "options": {
+ "env": {
+ "PATH": "${env:PATH};${config:idf.customExtraPaths}"
+ }
+ }
+ },
+ "options": {
+ "env": {
+ "PATH": "${env:PATH}:${config:idf.customExtraPaths}"
+ }
+ },
+ "problemMatcher": [
+ {
+ "owner": "cpp",
+ "fileLocation": [
+ "autoDetect",
+ "${workspaceFolder}"
+ ],
+ "pattern": {
+ "regexp": "^(.*?):(\\d+):(\\d*):?\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$",
+ "file": 1,
+ "line": 2,
+ "column": 3,
+ "severity": 4,
+ "message": 5
+ }
+ }
+ ],
+ "group": {
+ "kind": "build",
+ "isDefault": true
+ }
+ },
+ {
+ "label": "Set ESP-IDF Target",
+ "type": "shell",
+ "command": "${command:espIdf.setTarget}",
+ "problemMatcher": {
+ "owner": "cpp",
+ "fileLocation": [
+ "autoDetect",
+ "${workspaceFolder}"
+ ],
+ "pattern": {
+ "regexp": "^(.*?):(\\d+):(\\d*):?\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$",
+ "file": 1,
+ "line": 2,
+ "column": 3,
+ "severity": 4,
+ "message": 5
+ }
+ }
+ },
+ {
+ "label": "Clean - Clean the project",
+ "type": "shell",
+ "command": "${config:idf.pythonBinPath} ${config:idf.espIdfPath}/tools/idf.py fullclean",
+ "windows": {
+ "command": "${config:idf.pythonBinPathWin} ${config:idf.espIdfPathWin}\\tools\\idf.py fullclean",
+ "options": {
+ "env": {
+ "PATH": "${env:PATH};${config:idf.customExtraPaths}"
+ }
+ }
+ },
+ "options": {
+ "env": {
+ "PATH": "${env:PATH}:${config:idf.customExtraPaths}"
+ }
+ },
+ "problemMatcher": [
+ {
+ "owner": "cpp",
+ "fileLocation": [
+ "autoDetect",
+ "${workspaceFolder}"
+ ],
+ "pattern": {
+ "regexp": "^(.*?):(\\d+):(\\d*):?\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$",
+ "file": 1,
+ "line": 2,
+ "column": 3,
+ "severity": 4,
+ "message": 5
+ }
+ }
+ ]
+ },
+ {
+ "label": "Flash - Flash the device",
+ "type": "shell",
+ "command": "${config:idf.pythonBinPath} ${config:idf.espIdfPath}/tools/idf.py -p ${config:idf.port} -b ${config:idf.flashBaudRate} flash",
+ "windows": {
+ "command": "${config:idf.pythonBinPathWin} ${config:idf.espIdfPathWin}\\tools\\idf.py flash -p ${config:idf.portWin} -b ${config:idf.flashBaudRate}",
+ "options": {
+ "env": {
+ "PATH": "${env:PATH};${config:idf.customExtraPaths}"
+ }
+ }
+ },
+ "options": {
+ "env": {
+ "PATH": "${env:PATH}:${config:idf.customExtraPaths}"
+ }
+ },
+ "problemMatcher": [
+ {
+ "owner": "cpp",
+ "fileLocation": [
+ "autoDetect",
+ "${workspaceFolder}"
+ ],
+ "pattern": {
+ "regexp": "^(.*?):(\\d+):(\\d*):?\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$",
+ "file": 1,
+ "line": 2,
+ "column": 3,
+ "severity": 4,
+ "message": 5
+ }
+ }
+ ]
+ },
+ {
+ "label": "Monitor: Start the monitor",
+ "type": "shell",
+ "command": "${config:idf.pythonBinPath} ${config:idf.espIdfPath}/tools/idf.py -p ${config:idf.port} monitor",
+ "windows": {
+ "command": "${config:idf.pythonBinPathWin} ${config:idf.espIdfPathWin}\\tools\\idf.py -p ${config:idf.portWin} monitor",
+ "options": {
+ "env": {
+ "PATH": "${env:PATH};${config:idf.customExtraPaths}"
+ }
+ }
+ },
+ "options": {
+ "env": {
+ "PATH": "${env:PATH}:${config:idf.customExtraPaths}"
+ }
+ },
+ "problemMatcher": [
+ {
+ "owner": "cpp",
+ "fileLocation": [
+ "autoDetect",
+ "${workspaceFolder}"
+ ],
+ "pattern": {
+ "regexp": "^(.*?):(\\d+):(\\d*):?\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$",
+ "file": 1,
+ "line": 2,
+ "column": 3,
+ "severity": 4,
+ "message": 5
+ }
+ }
+ ],
+ "dependsOn": "Flash - Flash the device"
+ },
+ {
+ "label": "OpenOCD: Start openOCD",
+ "type": "shell",
+ "presentation": {
+ "echo": true,
+ "reveal": "never",
+ "focus": false,
+ "panel": "new"
+ },
+ "command": "openocd -s ${command:espIdf.getOpenOcdScriptValue} ${command:espIdf.getOpenOcdConfigs}",
+ "windows": {
+ "command": "openocd.exe -s ${command:espIdf.getOpenOcdScriptValue} ${command:espIdf.getOpenOcdConfigs}",
+ "options": {
+ "env": {
+ "PATH": "${env:PATH};${config:idf.customExtraPaths}"
+ }
+ }
+ },
+ "options": {
+ "env": {
+ "PATH": "${env:PATH}:${config:idf.customExtraPaths}"
+ }
+ },
+ "problemMatcher": {
+ "owner": "cpp",
+ "fileLocation": [
+ "autoDetect",
+ "${workspaceFolder}"
+ ],
+ "pattern": {
+ "regexp": "^(.*?):(\\d+):(\\d*):?\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$",
+ "file": 1,
+ "line": 2,
+ "column": 3,
+ "severity": 4,
+ "message": 5
+ }
+ }
+ },
+ {
+ "label": "adapter",
+ "type": "shell",
+ "command": "${config:idf.pythonBinPath}",
+ "isBackground": true,
+ "options": {
+ "env": {
+ "PATH": "${env:PATH}:${config:idf.customExtraPaths}",
+ "PYTHONPATH": "${command:espIdf.getExtensionPath}/esp_debug_adapter/debug_adapter"
+ }
+ },
+ "problemMatcher": {
+ "background": {
+ "beginsPattern": "\bDEBUG_ADAPTER_STARTED\b",
+ "endsPattern": "DEBUG_ADAPTER_READY2CONNECT",
+ "activeOnStart": true
+ },
+ "pattern": {
+ "regexp": "(\\d+)-(\\d+)-(\\d+)\\s(\\d+):(\\d+):(\\d+),(\\d+)\\s-(.+)\\s(ERROR)",
+ "file": 8,
+ "line": 2,
+ "column": 3,
+ "severity": 4,
+ "message": 9
+ }
+ },
+ "args": [
+ "${command:espIdf.getExtensionPath}/esp_debug_adapter/debug_adapter_main.py",
+ "-e",
+ "${workspaceFolder}/build/${command:espIdf.getProjectName}.elf",
+ "-s",
+ "$OPENOCD_SCRIPTS",
+ "-dn",
+ "esp32",
+ "-om",
+ "connect_to_instance",
+ "-t",
+ "xtensa-esp32-elf-"
+
+ ],
+ "windows": {
+ "command": "${config:idf.pythonBinPathWin}",
+ "options": {
+ "env": {
+ "PATH": "${env:PATH};${config:idf.customExtraPaths}",
+ "PYTHONPATH": "${command:espIdf.getExtensionPath}/esp_debug_adapter/debug_adapter"
+ }
+ }
+ }
+ }
+ ]
+} \ No newline at end of file
diff --git a/main/puzzle/neo/esp-neopuzzle/CMakeLists.txt b/main/puzzle/neo/esp-neopuzzle/CMakeLists.txt
new file mode 100644
index 0000000..fb90ef1
--- /dev/null
+++ b/main/puzzle/neo/esp-neopuzzle/CMakeLists.txt
@@ -0,0 +1,8 @@
+# For more information about build system see
+# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
+# The following five lines of boilerplate have to be in your project's
+# CMakeLists in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.16)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+project(esp-neopuzzle)
diff --git a/main/puzzle/neo/esp-neopuzzle/README.md b/main/puzzle/neo/esp-neopuzzle/README.md
new file mode 100644
index 0000000..2bd3097
--- /dev/null
+++ b/main/puzzle/neo/esp-neopuzzle/README.md
@@ -0,0 +1,35 @@
+| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
+| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
+
+# _Sample project_
+
+(See the README.md file in the upper level 'examples' directory for more information about examples.)
+
+This is the simplest buildable example. The example is used by command `idf.py create-project`
+that copies the project to user specified path and set it's name. For more information follow the [docs page](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html#start-a-new-project)
+
+
+
+## How to use example
+We encourage the users to use the example as a template for the new projects.
+A recommended way is to follow the instructions on a [docs page](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html#start-a-new-project).
+
+## Example folder contents
+
+The project **sample_project** contains one source file in C language [main.c](main/main.c). The file is located in folder [main](main).
+
+ESP-IDF projects are built using CMake. The project build configuration is contained in `CMakeLists.txt`
+files that provide set of directives and instructions describing the project's source files and targets
+(executable, library, or both).
+
+Below is short explanation of remaining files in the project folder.
+
+```
+├── CMakeLists.txt
+├── main
+│   ├── CMakeLists.txt
+│   └── main.c
+└── README.md This is the file you are currently reading
+```
+Additionally, the sample project contains Makefile and component.mk files, used for the legacy Make based build system.
+They are not used or needed when building with CMake and idf.py.
diff --git a/main/puzzle/neo/esp-neopuzzle/main/CMakeLists.txt b/main/puzzle/neo/esp-neopuzzle/main/CMakeLists.txt
new file mode 100644
index 0000000..cf2c455
--- /dev/null
+++ b/main/puzzle/neo/esp-neopuzzle/main/CMakeLists.txt
@@ -0,0 +1,2 @@
+idf_component_register(SRCS "main.c"
+ INCLUDE_DIRS ".")
diff --git a/main/puzzle/neo/esp-neopuzzle/main/main.c b/main/puzzle/neo/esp-neopuzzle/main/main.c
new file mode 100644
index 0000000..0210748
--- /dev/null
+++ b/main/puzzle/neo/esp-neopuzzle/main/main.c
@@ -0,0 +1,85 @@
+#include <stdio.h>
+#include <Wire.h>
+#include "Adafruit_NeoTrellis.h"
+
+#define MATRIX_SIZE 8
+#define INT_PIN 5 // Interrupt pin for the NeoTrellis
+
+enum NeoState {
+ NEO_UNINITIALIZED,
+ NEO_PLAYING,
+ NEO_SOLVED
+};
+
+Adafruit_NeoTrellis trellis;
+NeoState neoState = NEO_UNINITIALIZED;
+
+// Initialize the NeoTrellis matrix
+void initializeNeoMatrix() {
+ if (!trellis.begin()) {
+ Serial.println("Failed to initialize NeoTrellis");
+ while (1);
+ }
+
+ // Set all buttons to listen for presses and releases
+ for (int i = 0; i < MATRIX_SIZE; i++) {
+ for (int j = 0; j < MATRIX_SIZE; j++) {
+ trellis.activateKey(i * MATRIX_SIZE + j, SEESAW_KEYPAD_EDGE_RISING, true);
+ trellis.activateKey(i * MATRIX_SIZE + j, SEESAW_KEYPAD_EDGE_FALLING, true);
+ trellis.setPixelColor(i * MATRIX_SIZE + j, 0x000000); // Turn off LED
+ }
+ }
+ trellis.show();
+ neoState = NEO_PLAYING;
+}
+
+// Callback to handle button presses
+void buttonCallback(uint8_t x) {
+ uint8_t i = x / MATRIX_SIZE;
+ uint8_t j = x % MATRIX_SIZE;
+
+ // Toggle the central button and adjacent LEDs
+ toggleAdjacentLEDs(i, j);
+ if (isNeoPuzzleSolved()) {
+ neoState = NEO_SOLVED;
+ Serial.println("The NeoTrellis puzzle is solved!");
+ // Additional actions upon solving the puzzle can go here
+ }
+ trellis.show();
+}
+
+void toggleAdjacentLEDs(int x, int y) {
+ int idx = x * MATRIX_SIZE + y;
+ trellis.setPixelColor(idx, trellis.getPixelColor(idx) ^ 0xFFFFFF); // Toggle
+
+ // Adjacent LEDs
+ if (x > 0) trellis.setPixelColor((x-1) * MATRIX_SIZE + y, trellis.getPixelColor((x-1) * MATRIX_SIZE + y) ^ 0xFFFFFF);
+ if (x < MATRIX_SIZE - 1) trellis.setPixelColor((x+1) * MATRIX_SIZE + y, trellis.getPixelColor((x+1) * MATRIX_SIZE + y) ^ 0xFFFFFF);
+ if (y > 0) trellis.setPixelColor(x * MATRIX_SIZE + (y-1), trellis.getPixelColor(x * MATRIX_SIZE + (y-1)) ^ 0xFFFFFF);
+ if (y < MATRIX_SIZE - 1) trellis.setPixelColor(x * MATRIX_SIZE + (y+1), trellis.getPixelColor(x * MATRIX_SIZE + (y+1)) ^ 0xFFFFFF);
+}
+
+bool isNeoPuzzleSolved() {
+ for (int i = 0; i < MATRIX_SIZE; i++) {
+ for (int j = 0; j < MATRIX_SIZE; j++) {
+ if (trellis.getPixelColor(i * MATRIX_SIZE + j) != 0x000000) return false; // If any LED is on, puzzle is not solved
+ }
+ }
+ return true;
+}
+
+void setup() {
+ Serial.begin(115200);
+ trellis.begin(INT_PIN);
+ trellis.setBrightness(50); // Set brightness of LEDs (0-255)
+ initializeNeoMatrix();
+ trellis.registerCallback(buttonCallback);
+}
+
+void loop() {
+ if (neoState == NEO_PLAYING) {
+ if (trellis.read()) { // If there was a button event
+ trellis.show(); // Update the display
+ }
+ }
+}