From d27b6e702ffbb9eef75da08b614761c5baa093a3 Mon Sep 17 00:00:00 2001 From: Patedam Date: Sun, 1 Mar 2026 19:52:25 -0500 Subject: [PATCH] First submit, make led blink --- .gitignore | 85 ++++++++++++++++++ Provider/.gitignore | 1 + Provider/CMakeLists.txt | 6 ++ Provider/dependencies.lock | 21 +++++ Provider/esp_idf_project_configuration.json | 26 ++++++ Provider/main/CMakeLists.txt | 2 + Provider/main/connect.cpp | 0 Provider/main/idf_component.yml | 17 ++++ Provider/main/led_status.cpp | 44 +++++++++ Provider/main/main.cpp | 32 +++++++ Provider/main/types.hpp | 13 +++ ...-vscode.cpptools-extension-pack-1.5.1.vsix | Bin 0 -> 8270 bytes 12 files changed, 247 insertions(+) create mode 100644 .gitignore create mode 100644 Provider/.gitignore create mode 100644 Provider/CMakeLists.txt create mode 100644 Provider/dependencies.lock create mode 100644 Provider/esp_idf_project_configuration.json create mode 100644 Provider/main/CMakeLists.txt create mode 100644 Provider/main/connect.cpp create mode 100644 Provider/main/idf_component.yml create mode 100644 Provider/main/led_status.cpp create mode 100644 Provider/main/main.cpp create mode 100644 Provider/main/types.hpp create mode 100644 external/ms-vscode.cpptools-extension-pack-1.5.1.vsix diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..13dc40c --- /dev/null +++ b/.gitignore @@ -0,0 +1,85 @@ +@ -0,0 +1,78 @@ +# macOS +.DS_Store +.AppleDouble +.LSOverride + +# Directory metadata +.directory + +# Temporary files +*~ +*.swp +*.swo +*.bak +*.tmp + +# Log files +*.log + +# Build artifacts and directories +**/build/ +build/ +*.o +*.a +*.out +*.exe # For any host-side utilities compiled on Windows + +# ESP-IDF specific build outputs +*.bin +*.elf +*.map +flasher_args.json # Generated in build directory +sdkconfig.old +sdkconfig + +# ESP-IDF dependencies +# For older versions or manual component management +/components/.idf/ +**/components/.idf/ +# For modern ESP-IDF component manager +managed_components/ +# If ESP-IDF tools are installed/referenced locally to the project +.espressif/ + +# CMake generated files +CMakeCache.txt +CMakeFiles/ +cmake_install.cmake +install_manifest.txt +CTestTestfile.cmake + +# Python environment files +*.pyc +*.pyo +*.pyd +__pycache__/ +*.egg-info/ +dist/ + +# Virtual environment folders +venv/ +.venv/ +env/ + +# Language Servers +**/.clangd +**/.ccls-cache/ +**/compile_commands.json + +# Windows specific +Thumbs.db +ehthumbs.db +Desktop.ini + +# User-specific configuration files +*.user +*.workspace # General workspace files, can be from various tools +*.suo # Visual Studio Solution User Options +*.sln.docstates # Visual Studio + + +**/.cache/ +**/.devcontainer/ +**/.vscode/ +/Server diff --git a/Provider/.gitignore b/Provider/.gitignore new file mode 100644 index 0000000..f804ec5 --- /dev/null +++ b/Provider/.gitignore @@ -0,0 +1 @@ +external/ \ No newline at end of file diff --git a/Provider/CMakeLists.txt b/Provider/CMakeLists.txt new file mode 100644 index 0000000..4354294 --- /dev/null +++ b/Provider/CMakeLists.txt @@ -0,0 +1,6 @@ +# 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(Provider) diff --git a/Provider/dependencies.lock b/Provider/dependencies.lock new file mode 100644 index 0000000..732a10f --- /dev/null +++ b/Provider/dependencies.lock @@ -0,0 +1,21 @@ +dependencies: + espressif/led_strip: + component_hash: 28621486f77229aaf81c71f5e15d6fbf36c2949cf11094e07090593e659e7639 + dependencies: + - name: idf + require: private + version: '>=5.0' + source: + registry_url: https://components.espressif.com/ + type: service + version: 3.0.3 + idf: + source: + type: idf + version: 5.5.3 +direct_dependencies: +- espressif/led_strip +- idf +manifest_hash: f9f27a7bfd490a8f252ea50084db6f87c986509746a1f4fe61b5ce5bb0e44fcb +target: esp32s3 +version: 2.0.0 diff --git a/Provider/esp_idf_project_configuration.json b/Provider/esp_idf_project_configuration.json new file mode 100644 index 0000000..9847987 --- /dev/null +++ b/Provider/esp_idf_project_configuration.json @@ -0,0 +1,26 @@ +{ + "Provider-Default": { + "build": { + "compileArgs": [], + "ninjaArgs": [], + "buildDirectoryPath": "", + "sdkconfigDefaults": [], + "sdkconfigFilePath": "" + }, + "env": {}, + "flashBaudRate": "", + "idfTarget": "esp32s3", + "monitorBaudRate": "", + "openOCD": { + "debugLevel": -1, + "configs": [], + "args": [] + }, + "tasks": { + "preBuild": "", + "preFlash": "", + "postBuild": "", + "postFlash": "" + } + } +} diff --git a/Provider/main/CMakeLists.txt b/Provider/main/CMakeLists.txt new file mode 100644 index 0000000..5ebf314 --- /dev/null +++ b/Provider/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "main.cpp" + INCLUDE_DIRS ".") diff --git a/Provider/main/connect.cpp b/Provider/main/connect.cpp new file mode 100644 index 0000000..e69de29 diff --git a/Provider/main/idf_component.yml b/Provider/main/idf_component.yml new file mode 100644 index 0000000..88e3292 --- /dev/null +++ b/Provider/main/idf_component.yml @@ -0,0 +1,17 @@ +## IDF Component Manager Manifest File +dependencies: + ## Required IDF version + idf: + version: '>=4.1.0' + # # Put list of dependencies here + # # For components maintained by Espressif: + # component: "~1.0.0" + # # For 3rd party components: + # username/component: ">=1.0.0,<2.0.0" + # username2/component2: + # version: "~1.0.0" + # # For transient dependencies `public` flag can be set. + # # `public` flag doesn't have an effect dependencies of the `main` component. + # # All dependencies of `main` are public by default. + # public: true + espressif/led_strip: ^3.0.3 diff --git a/Provider/main/led_status.cpp b/Provider/main/led_status.cpp new file mode 100644 index 0000000..de9b7dc --- /dev/null +++ b/Provider/main/led_status.cpp @@ -0,0 +1,44 @@ +// Project includes +#include "types.hpp" + +// SDK Includes +#include "led_strip.h" + +enum class led_status : uint8 { Connecting, Ready, Failed }; + +// Could be a config but its the GPIO on my ESP32-S3-ETH +#define LED_GPIO GPIO_NUM_21 + +static led_strip_handle_t led_strip; + +static void setup_led(void) { + /* LED strip initialization with the GPIO and pixels number*/ + led_strip_config_t strip_config = {}; + strip_config.strip_gpio_num = LED_GPIO; + strip_config.max_leds = 1; // at least one LED on board + + led_strip_rmt_config_t rmt_config = {}; + rmt_config.resolution_hz = 10 * 1000 * 1000; // 10MHz + rmt_config.flags.with_dma = false; + ESP_ERROR_CHECK( + led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip)); + + led_strip_clear(led_strip); +} + +static void destroy_led(void) { led_strip_clear(led_strip); } + +void set_led_status(led_status status) { + switch (status) { + case led_status::Connecting: + led_strip_set_pixel(led_strip, 0, 0, 0, 255); + break; + case led_status::Ready: + led_strip_set_pixel(led_strip, 0, 0, 255, 0); + break; + case led_status::Failed: + led_strip_set_pixel(led_strip, 0, 255, 0, 0); + break; + } + led_strip_refresh(led_strip); +} \ No newline at end of file diff --git a/Provider/main/main.cpp b/Provider/main/main.cpp new file mode 100644 index 0000000..73b8e2e --- /dev/null +++ b/Provider/main/main.cpp @@ -0,0 +1,32 @@ +// STD Lib +#include + +// SDK +#include "driver/gpio.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "sdkconfig.h" +#include "soc/gpio_num.h" + +// Project cpp +#include "connect.cpp" +#include "led_status.cpp" + +extern "C" void app_main() { + setup_led(); + printf("Hello, Worldi!\n"); + set_led_status(led_status::Connecting); + + vTaskDelay(1000 / portTICK_PERIOD_MS); + + set_led_status(led_status::Ready); + + vTaskDelay(1000 / portTICK_PERIOD_MS); + + set_led_status(led_status::Failed); + + vTaskDelay(1000 / portTICK_PERIOD_MS); + + destroy_led(); +} diff --git a/Provider/main/types.hpp b/Provider/main/types.hpp new file mode 100644 index 0000000..587036e --- /dev/null +++ b/Provider/main/types.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include + +using uint8 = uint8_t; +using uint16 = uint16_t; +using uint32 = uint32_t; +using uint64 = uint64_t; + +using int8 = int8_t; +using int16 = int16_t; +using int32 = int32_t; +using int64 = int64_t; \ No newline at end of file diff --git a/external/ms-vscode.cpptools-extension-pack-1.5.1.vsix b/external/ms-vscode.cpptools-extension-pack-1.5.1.vsix new file mode 100644 index 0000000000000000000000000000000000000000..e766cc45e6f5c6b141eb40a505c5743c9135cb31 GIT binary patch literal 8270 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 M