From d8ca24031bea6ac2859e47c70764d6ba7e27721a Mon Sep 17 00:00:00 2001 From: maartin0 Date: Sun, 23 Mar 2025 00:02:39 +0000 Subject: [PATCH] add Arduino LED and Wi-Fi SDKs Adds two esp32 example projects using the espressif/arduino-esp32 library to demonstrate Wi-Fi scanning and a simple LED blink example --- .github/workflows/build-arduino-esp.yml | 46 ++++++++++++ README.md | 4 +- arduino-esp32-led-blink-sdk/CMakeLists.txt | 6 ++ arduino-esp32-led-blink-sdk/README.md | 57 +++++++++++++++ arduino-esp32-led-blink-sdk/diagram.json | 36 +++++++++ .../main/BridgingHeader.h | 27 +++++++ .../main/CMakeLists.txt | 73 +++++++++++++++++++ .../main/Kconfig.projbuild | 8 ++ arduino-esp32-led-blink-sdk/main/Led.swift | 23 ++++++ arduino-esp32-led-blink-sdk/main/Main.swift | 28 +++++++ arduino-esp32-led-blink-sdk/main/component.mk | 8 ++ .../main/idf_component.yml | 19 +++++ .../sdkconfig.defaults | 4 + arduino-esp32-led-blink-sdk/wokwi.toml | 8 ++ arduino-esp32-wifi-scan-sdk/CMakeLists.txt | 6 ++ arduino-esp32-wifi-scan-sdk/README.md | 48 ++++++++++++ .../main/ArduinoString.swift | 23 ++++++ .../main/BridgingHeader.h | 31 ++++++++ .../main/CMakeLists.txt | 73 +++++++++++++++++++ .../main/Kconfig.projbuild | 8 ++ arduino-esp32-wifi-scan-sdk/main/Main.swift | 26 +++++++ arduino-esp32-wifi-scan-sdk/main/component.mk | 8 ++ .../main/idf_component.yml | 19 +++++ .../sdkconfig.defaults | 4 + 24 files changed, 592 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/build-arduino-esp.yml create mode 100644 arduino-esp32-led-blink-sdk/CMakeLists.txt create mode 100644 arduino-esp32-led-blink-sdk/README.md create mode 100644 arduino-esp32-led-blink-sdk/diagram.json create mode 100644 arduino-esp32-led-blink-sdk/main/BridgingHeader.h create mode 100644 arduino-esp32-led-blink-sdk/main/CMakeLists.txt create mode 100644 arduino-esp32-led-blink-sdk/main/Kconfig.projbuild create mode 100644 arduino-esp32-led-blink-sdk/main/Led.swift create mode 100644 arduino-esp32-led-blink-sdk/main/Main.swift create mode 100644 arduino-esp32-led-blink-sdk/main/component.mk create mode 100644 arduino-esp32-led-blink-sdk/main/idf_component.yml create mode 100644 arduino-esp32-led-blink-sdk/sdkconfig.defaults create mode 100644 arduino-esp32-led-blink-sdk/wokwi.toml create mode 100644 arduino-esp32-wifi-scan-sdk/CMakeLists.txt create mode 100644 arduino-esp32-wifi-scan-sdk/README.md create mode 100644 arduino-esp32-wifi-scan-sdk/main/ArduinoString.swift create mode 100644 arduino-esp32-wifi-scan-sdk/main/BridgingHeader.h create mode 100644 arduino-esp32-wifi-scan-sdk/main/CMakeLists.txt create mode 100644 arduino-esp32-wifi-scan-sdk/main/Kconfig.projbuild create mode 100644 arduino-esp32-wifi-scan-sdk/main/Main.swift create mode 100644 arduino-esp32-wifi-scan-sdk/main/component.mk create mode 100644 arduino-esp32-wifi-scan-sdk/main/idf_component.yml create mode 100644 arduino-esp32-wifi-scan-sdk/sdkconfig.defaults diff --git a/.github/workflows/build-arduino-esp.yml b/.github/workflows/build-arduino-esp.yml new file mode 100644 index 0000000..c9b49ee --- /dev/null +++ b/.github/workflows/build-arduino-esp.yml @@ -0,0 +1,46 @@ +name: Build Arduino ESP Examples + +on: + push: + branches: ["main"] + pull_request: + branches: ["main"] + schedule: + # Build on Mondays at 9am PST every week + - cron: '0 17 * * 1' + +jobs: + build-arduino-esp: + runs-on: ubuntu-24.04 + container: espressif/idf:v5.4 + strategy: + fail-fast: false + matrix: + example: [arduino-esp32-led-blink-sdk, arduino-esp32-wifi-scan-sdk] + swift: [swift-DEVELOPMENT-SNAPSHOT-2025-03-17-a] + + steps: + - name: Checkout repo + uses: actions/checkout@v4 + + - name: Install apt dependencies + run: | + apt-get -qq update + apt-get -qq -y install pkg-config libstdc++6 + + - name: Install ${{ matrix.swift }} + run: | + wget -q https://download.swift.org/development/ubuntu2404/${{ matrix.swift }}/${{ matrix.swift }}-ubuntu24.04.tar.gz + tar xzf ${{ matrix.swift }}-ubuntu24.04.tar.gz + export PATH="`pwd`/${{ matrix.swift }}-ubuntu24.04/usr/bin/:$PATH" + echo "PATH=$PATH" >> $GITHUB_ENV + swiftc --version + + - name: Build ${{ matrix.example }} + run: | + cd $IDF_PATH + . ./export.sh + cd - + cd ${{ matrix.example }} + idf.py set-target esp32c6 + idf.py build diff --git a/README.md b/README.md index c925ae5..514598f 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ This repository is a set of demonstration projects of **Embedded Swift**. Embedd Each example in this repository contains build and deployment instructions, however there are a couple common steps needed for many of the examples included below: 1. Install the latest downloadable 'main' [Development Snapshot](https://www.swift.org/install/macos/#development-snapshots) from swift.org to use Embedded Swift. Public releases of Swift do not yet support Embedded Swift. - + You can follow the [tutorial here](https://apple.github.io/swift-matter-examples/tutorials/swiftmatterexamples/setup-macos/) for instructions on installing and using nighly Swift toolchains. 2. Install [`uv`](https://github.com/astral-sh/uv) "an extremely fast Python package and project manager". @@ -29,6 +29,8 @@ Each example in this repository contains build and deployment instructions, howe | ---- | -------- | --- | ----------- | ----- | | [esp32-led-blink-sdk](./esp32-led-blink-sdk) | ESP32-C6-Bug | ESP-IDF SDK | Blink an LED repeatedly with Swift & the ESP-IDF. | | | [esp32-led-strip-sdk](./esp32-led-strip-sdk) | ESP32-C6-DevKitC-1 | ESP-IDF SDK | Control NeoPixel LEDs with Swift & the ESP-IDF. | | +| [arduino-esp32-led-blink-sdk](./arduino-esp32-led-blink-sdk) | ESP32-C6-Bug | ESP-IDF SDK | Blink an LED repeatedly with Swift, the ESP-IDF and the Arduino libraries. | | +| [arduino-esp32-wifi-scan-sdk](./arduino-esp32-wifi-scan-sdk) | ESP32-C6-DevKitC-1 | ESP-IDF SDK | Blink an LED repeatedly with Swift, the ESP-IDF and the Arduino libraries. | | | [nrfx-blink-sdk](./nrfx-blink-sdk) | nRF52840-DK | Zephyr SDK | Blink an LED repeatedly with Swift & Zephyr. | | | [nuttx-riscv-blink](./nuttx-riscv-blink) | QEMU | NuttX | Blink a virualized led in QEMU using the Apache NuttX RTOS | | | [pico-blink-sdk](./pico-blink-sdk) | Raspberry Pi Pico, Pico 2 | Pico SDK | Blink an LED repeatedly with Swift & the Pico SDK. | | diff --git a/arduino-esp32-led-blink-sdk/CMakeLists.txt b/arduino-esp32-led-blink-sdk/CMakeLists.txt new file mode 100644 index 0000000..bda6977 --- /dev/null +++ b/arduino-esp32-led-blink-sdk/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following 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.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(app-template) diff --git a/arduino-esp32-led-blink-sdk/README.md b/arduino-esp32-led-blink-sdk/README.md new file mode 100644 index 0000000..1ad5e52 --- /dev/null +++ b/arduino-esp32-led-blink-sdk/README.md @@ -0,0 +1,57 @@ +# arduino-esp32-led-blink-sdk + +This example demonstrates how to integrate with the ESP-IDF SDK via CMake and how to use the Arduino GPIO library to control an LED from Swift. This example is specifically made for the RISC-V MCUs from ESP32 (the Xtensa MCUs are not currently supported by Swift). + +## Requirements + +- Set up **version v5.4** (required for this `arduino-esp32` version) of the [ESP-IDF](https://docs.espressif.com/projects/esp-idf/en/v5.4/esp32/) development environment. Follow the steps in the [ESP32-C6 "Get Started" guide](https://docs.espressif.com/projects/esp-idf/en/v5.4/esp32c6/get-started/index.html). + - Make sure you specifically set up development for the RISC-V ESP32-C6, and not the Xtensa based products. + - If you have a different version of ESP-IDF installed, make sure to also delete `~/.espressif` before running `install.sh` + +```sh +rm -rf ~/esp-idf ~/.espressif # Remove old installation files +git clone --recurse-submodules https://github.com/espressif/esp-idf.git ~/esp-idf +cd ~/esp-idf +git checkout release/v5.4 +git submodule update --init --recursive +./install.sh +idf_tools.py install-python-env +. ./export.sh +``` + +- Before trying to use Swift with the ESP-IDF SDK, make sure your environment works and can build the provided C/C++ sample projects, in particular: + - Try building and running the "get-started/blink" example from ESP-IDF written in C. + +## Building + +- Make sure you have a recent nightly Swift toolchain that has Embedded Swift support. +- If needed, run export.sh to get access to the idf.py script from ESP-IDF. +- Specify the nightly toolchain to be used via the `TOOLCHAINS` environment variable and the target board type by using `idf.py set-target`. +```sh +cd arduino-esp32-led-blink-sdk +export TOOLCHAINS=... +. /export.sh +idf.py set-target esp32c6 +idf.py build +``` + +## Running + +- Connect the Esp32-C6-Bug board (or any other board with integrated LED on GPIO pin 8) over a USB cable to your Mac. Alternatively you can just connect external LED to GPIO pin 8 on any other board. +- Connect RX pin of USB-UART converter to TX0 pin of your board if you need serial output. You may also need to connect GND converter pin to the GND pin of the board. +- Use `idf.py` to upload the firmware and to run it: + +```sh +idf.py flash +``` + +- The LED should be blinking now. + +### Simulating in VS Code + +- Build the project, to generate binaries for simulation +- Install [Wokwi for VS Code](https://docs.wokwi.com/vscode/getting-started/). +- Open the `diagram.json` file. +- Click the Play button to start simulation. +- Click the Pause button to freeze simulation and display states of GPIOs. + diff --git a/arduino-esp32-led-blink-sdk/diagram.json b/arduino-esp32-led-blink-sdk/diagram.json new file mode 100644 index 0000000..7d76a53 --- /dev/null +++ b/arduino-esp32-led-blink-sdk/diagram.json @@ -0,0 +1,36 @@ +{ + "version": 1, + "author": "", + "editor": "wokwi", + "parts": [ + { + "type": "board-esp32-c6-devkitc-1", + "id": "esp", + "top": 0, + "left": 0, + "attrs": { "builder": "esp-idf" } + }, + { + "type": "wokwi-resistor", + "id": "r1", + "top": 119.15, + "left": -76.8, + "attrs": { "value": "1000" } + }, + { + "type": "wokwi-led", + "id": "led1", + "top": 25.2, + "left": -111.4, + "attrs": { "color": "red" } + } + ], + "connections": [ + [ "esp:TX", "$serialMonitor:RX", "", [] ], + [ "esp:RX", "$serialMonitor:TX", "", [] ], + [ "r1:2", "esp:8", "red", [ "v0" ] ], + [ "r1:1", "led1:A", "red", [ "h0" ] ], + [ "led1:C", "esp:GND.1", "black", [ "v0" ] ] + ], + "dependencies": {} +} diff --git a/arduino-esp32-led-blink-sdk/main/BridgingHeader.h b/arduino-esp32-led-blink-sdk/main/BridgingHeader.h new file mode 100644 index 0000000..c0a1906 --- /dev/null +++ b/arduino-esp32-led-blink-sdk/main/BridgingHeader.h @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors. +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// +//===----------------------------------------------------------------------===// + +// For some reason swiftc's clang++ defines `__UINT32_TYPE__` as `unsigned int` (g++'s x86 behaviour) not `long unsigned int` (g++'s riscv32 behaviour) +#undef __UINT32_TYPE__ +#undef uint32_t +#define __UINT32_TYPE__ long unsigned int +#define uint32_t __UINT32_TYPE__ +#define _UINT32_T_DECLARED + +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/gpio.h" +#include "sdkconfig.h" + +#include diff --git a/arduino-esp32-led-blink-sdk/main/CMakeLists.txt b/arduino-esp32-led-blink-sdk/main/CMakeLists.txt new file mode 100644 index 0000000..a1314a1 --- /dev/null +++ b/arduino-esp32-led-blink-sdk/main/CMakeLists.txt @@ -0,0 +1,73 @@ +# Register the app as an IDF component +idf_component_register( + SRCS /dev/null # We don't have any C++ sources + PRIV_INCLUDE_DIRS "." + REQUIRES arduino +) + +idf_build_get_property(target IDF_TARGET) +idf_build_get_property(arch IDF_TARGET_ARCH) + +if("${arch}" STREQUAL "xtensa") + message(FATAL_ERROR "Not supported target: ${target}") +endif() + +# Extract the -march flag and remove any vendor-specific extensions (_x*) +string(REGEX MATCH "-march=[^ ]+" march_flag "${CMAKE_C_FLAGS}") +string(REGEX REPLACE "_x[^ ]*" "" march_flag "${march_flag}") + +# Extract the -mabi flag or set a default value if not present +string(REGEX MATCH "-mabi=[^ ]+" mabi_flag "${CMAKE_C_FLAGS}") +if("${mabi_flag}" STREQUAL "") + set(mabi_flag "-mabi=ilp32") +endif() + +# Clear the default COMPILE_OPTIONS which include a lot of C/C++ specific compiler flags that the Swift compiler will not accept +get_target_property(var ${COMPONENT_LIB} COMPILE_OPTIONS) +set_target_properties(${COMPONENT_LIB} PROPERTIES COMPILE_OPTIONS "") + +# Compute -Xcc flags to set up the C and C++ header search paths for Swift (for bridging header). +set(SWIFT_INCLUDES) +foreach(dir ${CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES}) + string(CONCAT SWIFT_INCLUDES ${SWIFT_INCLUDES} "-Xcc ") + string(CONCAT SWIFT_INCLUDES ${SWIFT_INCLUDES} "-I${dir} ") +endforeach() +foreach(dir ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}) + string(CONCAT SWIFT_INCLUDES ${SWIFT_INCLUDES} "-Xcc ") + string(CONCAT SWIFT_INCLUDES ${SWIFT_INCLUDES} "-I${dir} ") +endforeach() + +# Swift compiler flags to build in Embedded Swift mode, optimize for size, choose the right ISA, ABI, etc. +target_compile_options(${COMPONENT_LIB} PUBLIC "$<$:SHELL: + -target riscv32-none-none-eabi + -Xfrontend -function-sections -enable-experimental-feature Embedded -wmo -parse-as-library -Osize -cxx-interoperability-mode=default + -Xcc ${march_flag} -Xcc ${mabi_flag} -Xcc -fno-pic -Xcc -fno-pie -Xcc -fno-exceptions + + -pch-output-dir /tmp + -Xfrontend -enable-single-module-llvm-emission + + ${SWIFT_INCLUDES} + + -import-bridging-header ${CMAKE_CURRENT_LIST_DIR}/BridgingHeader.h + >") + +# Enable Swift support in CMake, force Whole Module builds (required by Embedded Swift), and use "CMAKE_Swift_COMPILER_WORKS" to +# skip the trial compilations which don't (yet) correctly work when cross-compiling. +set(CMAKE_Swift_COMPILER_WORKS YES) +set(CMAKE_Swift_COMPILATION_MODE_DEFAULT wholemodule) +set(CMAKE_Swift_COMPILATION_MODE wholemodule) +enable_language(Swift) + +# List of Swift source files to build. +target_sources(${COMPONENT_LIB} + PRIVATE + Main.swift + Led.swift +) + +add_custom_command( + TARGET ${COMPONENT_LIB} + POST_BUILD + COMMAND ${CMAKE_OBJCOPY} --remove-section .swift_modhash + $ $ +) diff --git a/arduino-esp32-led-blink-sdk/main/Kconfig.projbuild b/arduino-esp32-led-blink-sdk/main/Kconfig.projbuild new file mode 100644 index 0000000..94f2f0e --- /dev/null +++ b/arduino-esp32-led-blink-sdk/main/Kconfig.projbuild @@ -0,0 +1,8 @@ +# put here your custom config value +menu "Example Configuration" +config LED_BLINK_INTERVAL_MS + int "LED blinking interval / ms" + default 500 + help + Interval in milliseconds between turning the LED on/off +endmenu diff --git a/arduino-esp32-led-blink-sdk/main/Led.swift b/arduino-esp32-led-blink-sdk/main/Led.swift new file mode 100644 index 0000000..8a50414 --- /dev/null +++ b/arduino-esp32-led-blink-sdk/main/Led.swift @@ -0,0 +1,23 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors. +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// +//===----------------------------------------------------------------------===// + +// A simple "overlay" to provide nicer APIs in Swift +struct Led { + var ledPin: UInt8 + init(gpioPin: gpio_num_t) { + ledPin = UInt8(gpioPin.rawValue) + pinMode(ledPin, UInt8(OUTPUT)) + } + + func setLed(value: Bool) { + digitalWrite(ledPin, value ? 1 : 0) + } +} diff --git a/arduino-esp32-led-blink-sdk/main/Main.swift b/arduino-esp32-led-blink-sdk/main/Main.swift new file mode 100644 index 0000000..7509e93 --- /dev/null +++ b/arduino-esp32-led-blink-sdk/main/Main.swift @@ -0,0 +1,28 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors. +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// +//===----------------------------------------------------------------------===// + +// The code will blink an LED on GPIO8. To change the pin, modify Led(gpioPin: GPIO_NUM_8) + +var ledValue: Bool = false +var led: Led? + +@_cdecl("_Z5setupv") +func setup() { + print("Hello from Swift on ESP32-C6!") + led = Led(gpioPin: GPIO_NUM_8) +} + +@_cdecl("_Z4loopv") +func loop() { + led?.setLed(value: ledValue) + ledValue.toggle() // Toggle the boolean value + delay(UInt(CONFIG_LED_BLINK_INTERVAL_MS)) +} diff --git a/arduino-esp32-led-blink-sdk/main/component.mk b/arduino-esp32-led-blink-sdk/main/component.mk new file mode 100644 index 0000000..61f8990 --- /dev/null +++ b/arduino-esp32-led-blink-sdk/main/component.mk @@ -0,0 +1,8 @@ +# +# Main component makefile. +# +# This Makefile can be left empty. By default, it will take the sources in the +# src/ directory, compile them and link them into lib(subdirectory_name).a +# in the build directory. This behaviour is entirely configurable, +# please read the ESP-IDF documents if you need to do this. +# diff --git a/arduino-esp32-led-blink-sdk/main/idf_component.yml b/arduino-esp32-led-blink-sdk/main/idf_component.yml new file mode 100644 index 0000000..cdf6c3d --- /dev/null +++ b/arduino-esp32-led-blink-sdk/main/idf_component.yml @@ -0,0 +1,19 @@ +## IDF Component Manager Manifest File +dependencies: + # # 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 + + ## Required IDF version + idf: ">=5.3,<5.5" + arduino: # Can't be defined as the espressif/arduino-esp32 shorthand since the library name must be 'arduino' for libraries that depend on it + git: https://github.com/espressif/arduino-esp32.git + version: 3.2.0 diff --git a/arduino-esp32-led-blink-sdk/sdkconfig.defaults b/arduino-esp32-led-blink-sdk/sdkconfig.defaults new file mode 100644 index 0000000..d4f9762 --- /dev/null +++ b/arduino-esp32-led-blink-sdk/sdkconfig.defaults @@ -0,0 +1,4 @@ +CONFIG_FREERTOS_HZ=1000 +CONFIG_MBEDTLS_PSK_MODES=y +CONFIG_MBEDTLS_KEY_EXCHANGE_PSK=y +CONFIG_AUTOSTART_ARDUINO=y diff --git a/arduino-esp32-led-blink-sdk/wokwi.toml b/arduino-esp32-led-blink-sdk/wokwi.toml new file mode 100644 index 0000000..ab73f47 --- /dev/null +++ b/arduino-esp32-led-blink-sdk/wokwi.toml @@ -0,0 +1,8 @@ +# Wokwi Configuration File +# Reference: https://docs.wokwi.com/vscode/project-config +[wokwi] +version = 1 +firmware = 'build/flasher_args.json' +elf = 'build/main.elf' +# gdbServerPort=3333 + diff --git a/arduino-esp32-wifi-scan-sdk/CMakeLists.txt b/arduino-esp32-wifi-scan-sdk/CMakeLists.txt new file mode 100644 index 0000000..bda6977 --- /dev/null +++ b/arduino-esp32-wifi-scan-sdk/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following 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.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(app-template) diff --git a/arduino-esp32-wifi-scan-sdk/README.md b/arduino-esp32-wifi-scan-sdk/README.md new file mode 100644 index 0000000..b7f3389 --- /dev/null +++ b/arduino-esp32-wifi-scan-sdk/README.md @@ -0,0 +1,48 @@ +# arduino-esp32-wifi-scan-sdk + +This example demonstrates how to integrate with the ESP-IDF SDK via CMake and how to use the Arduino Wi-Fi library to scan for nearby networks from Swift. This example is specifically made for the RISC-V MCUs from ESP32 (the Xtensa MCUs are not currently supported by Swift). + +## Requirements + +- Set up **version v5.4** (required for this `arduino-esp32` version) of the [ESP-IDF](https://docs.espressif.com/projects/esp-idf/en/v5.4/esp32/) development environment. Follow the steps in the [ESP32-C6 "Get Started" guide](https://docs.espressif.com/projects/esp-idf/en/v5.4/esp32c6/get-started/index.html). + - Make sure you specifically set up development for the RISC-V ESP32-C6, and not the Xtensa based products. + - If you have a different version of ESP-IDF installed, make sure to also delete `~/.espressif` before running `install.sh` + +```sh +rm -rf ~/esp-idf ~/.espressif # Remove old installation files +git clone --recurse-submodules https://github.com/espressif/esp-idf.git ~/esp-idf +cd ~/esp-idf +git checkout release/v5.4 +git submodule update --init --recursive +./install.sh +idf_tools.py install-python-env +. ./export.sh +``` + +- Before trying to use Swift with the ESP-IDF SDK, make sure your environment works and can build the provided C/C++ sample projects, in particular: + - Try building and running the "get-started/blink" example from ESP-IDF written in C. + +## Building + +- Make sure you have a recent nightly Swift toolchain that has Embedded Swift support. +- If needed, run export.sh to get access to the idf.py script from ESP-IDF. +- Specify the nightly toolchain to be used via the `TOOLCHAINS` environment variable and the target board type by using `idf.py set-target`. +```sh +cd arduino-esp32-wifi-scan-sdk +export TOOLCHAINS=... +. /export.sh +idf.py set-target esp32c6 +idf.py build +``` + +## Running + +- Connect any board with an ESP32-C6 +- Connect the RX and TX pins of your USB-UART converter to the TX0 and RX0 respective pins of your board. You may also need to connect the GND converter pin to the GND pin of the board. +- Use `idf.py` to upload the firmware and to run it: + +```sh +idf.py flash monitor +``` + +- You should see a list of discovered Wi-Fi APs being printed every 5 seconds diff --git a/arduino-esp32-wifi-scan-sdk/main/ArduinoString.swift b/arduino-esp32-wifi-scan-sdk/main/ArduinoString.swift new file mode 100644 index 0000000..a3610a6 --- /dev/null +++ b/arduino-esp32-wifi-scan-sdk/main/ArduinoString.swift @@ -0,0 +1,23 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors. +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// +//===----------------------------------------------------------------------===// + +public typealias ArduinoString = String + +extension ArduinoString: CustomStringConvertible { + public var description: Swift.String { + let size = self.length() + 1 + let buffer = UnsafeMutablePointer.allocate(capacity: Int(size)) + self.getBytes(buffer, size) + let result = Swift.String(cString: UnsafePointer(buffer)) + buffer.deallocate() + return result + } +} diff --git a/arduino-esp32-wifi-scan-sdk/main/BridgingHeader.h b/arduino-esp32-wifi-scan-sdk/main/BridgingHeader.h new file mode 100644 index 0000000..3d6ac7e --- /dev/null +++ b/arduino-esp32-wifi-scan-sdk/main/BridgingHeader.h @@ -0,0 +1,31 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors. +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// +//===----------------------------------------------------------------------===// + +// For some reason swiftc's clang++ defines `__UINT32_TYPE__` as `unsigned int` (g++'s x86 behaviour) not `long unsigned int` (g++'s riscv32 behaviour) +#undef __UINT32_TYPE__ +#undef uint32_t +#define __UINT32_TYPE__ long unsigned int +#define uint32_t __UINT32_TYPE__ +#define _UINT32_T_DECLARED + +#include +#include +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/gpio.h" +#include "sdkconfig.h" + +#include +#include +#include diff --git a/arduino-esp32-wifi-scan-sdk/main/CMakeLists.txt b/arduino-esp32-wifi-scan-sdk/main/CMakeLists.txt new file mode 100644 index 0000000..a50a389 --- /dev/null +++ b/arduino-esp32-wifi-scan-sdk/main/CMakeLists.txt @@ -0,0 +1,73 @@ +# Register the app as an IDF component +idf_component_register( + SRCS /dev/null # We don't have any C++ sources + PRIV_INCLUDE_DIRS "." + REQUIRES arduino +) + +idf_build_get_property(target IDF_TARGET) +idf_build_get_property(arch IDF_TARGET_ARCH) + +if("${arch}" STREQUAL "xtensa") + message(FATAL_ERROR "Not supported target: ${target}") +endif() + +# Extract the -march flag and remove any vendor-specific extensions (_x*) +string(REGEX MATCH "-march=[^ ]+" march_flag "${CMAKE_C_FLAGS}") +string(REGEX REPLACE "_x[^ ]*" "" march_flag "${march_flag}") + +# Extract the -mabi flag or set a default value if not present +string(REGEX MATCH "-mabi=[^ ]+" mabi_flag "${CMAKE_C_FLAGS}") +if("${mabi_flag}" STREQUAL "") + set(mabi_flag "-mabi=ilp32") +endif() + +# Clear the default COMPILE_OPTIONS which include a lot of C/C++ specific compiler flags that the Swift compiler will not accept +get_target_property(var ${COMPONENT_LIB} COMPILE_OPTIONS) +set_target_properties(${COMPONENT_LIB} PROPERTIES COMPILE_OPTIONS "") + +# Compute -Xcc flags to set up the C and C++ header search paths for Swift (for bridging header). +set(SWIFT_INCLUDES) +foreach(dir ${CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES}) + string(CONCAT SWIFT_INCLUDES ${SWIFT_INCLUDES} "-Xcc ") + string(CONCAT SWIFT_INCLUDES ${SWIFT_INCLUDES} "-I${dir} ") +endforeach() +foreach(dir ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}) + string(CONCAT SWIFT_INCLUDES ${SWIFT_INCLUDES} "-Xcc ") + string(CONCAT SWIFT_INCLUDES ${SWIFT_INCLUDES} "-I${dir} ") +endforeach() + +# Swift compiler flags to build in Embedded Swift mode, optimize for size, choose the right ISA, ABI, etc. +target_compile_options(${COMPONENT_LIB} PUBLIC "$<$:SHELL: + -target riscv32-none-none-eabi + -Xfrontend -function-sections -enable-experimental-feature Embedded -wmo -parse-as-library -Osize -cxx-interoperability-mode=default + -Xcc ${march_flag} -Xcc ${mabi_flag} -Xcc -fno-pic -Xcc -fno-pie -Xcc -fno-exceptions + + -pch-output-dir /tmp + -Xfrontend -enable-single-module-llvm-emission + + ${SWIFT_INCLUDES} + + -import-bridging-header ${CMAKE_CURRENT_LIST_DIR}/BridgingHeader.h + >") + +# Enable Swift support in CMake, force Whole Module builds (required by Embedded Swift), and use "CMAKE_Swift_COMPILER_WORKS" to +# skip the trial compilations which don't (yet) correctly work when cross-compiling. +set(CMAKE_Swift_COMPILER_WORKS YES) +set(CMAKE_Swift_COMPILATION_MODE_DEFAULT wholemodule) +set(CMAKE_Swift_COMPILATION_MODE wholemodule) +enable_language(Swift) + +# List of Swift source files to build. +target_sources(${COMPONENT_LIB} + PRIVATE + Main.swift + ArduinoString.swift +) + +add_custom_command( + TARGET ${COMPONENT_LIB} + POST_BUILD + COMMAND ${CMAKE_OBJCOPY} --remove-section .swift_modhash + $ $ +) diff --git a/arduino-esp32-wifi-scan-sdk/main/Kconfig.projbuild b/arduino-esp32-wifi-scan-sdk/main/Kconfig.projbuild new file mode 100644 index 0000000..befc4ef --- /dev/null +++ b/arduino-esp32-wifi-scan-sdk/main/Kconfig.projbuild @@ -0,0 +1,8 @@ +# put here your custom config value +menu "Example Configuration" +config WIFI_SCAN_INTERVAL_MS + int "WiFi network scanning interval / ms" + default 5000 + help + Interval in milliseconds between scanning for networks +endmenu diff --git a/arduino-esp32-wifi-scan-sdk/main/Main.swift b/arduino-esp32-wifi-scan-sdk/main/Main.swift new file mode 100644 index 0000000..6326eca --- /dev/null +++ b/arduino-esp32-wifi-scan-sdk/main/Main.swift @@ -0,0 +1,26 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift open source project +// +// Copyright (c) 2025 Apple Inc. and the Swift project authors. +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// +//===----------------------------------------------------------------------===// + +@_cdecl("_Z5setupv") +func setup() { + print("Hello from Swift on a ESP32-C6!") +} + +@_cdecl("_Z4loopv") +func loop() { + print("Scanning...") + let count = WiFi.scanNetworks(false, true) + print("Found \(count) networks:") + for i in 0..=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 + + ## Required IDF version + idf: ">=5.3,<5.5" + arduino: # Can't be defined as the espressif/arduino-esp32 shorthand since the library name must be 'arduino' for libraries that depend on it + git: https://github.com/espressif/arduino-esp32.git + version: 3.2.0 diff --git a/arduino-esp32-wifi-scan-sdk/sdkconfig.defaults b/arduino-esp32-wifi-scan-sdk/sdkconfig.defaults new file mode 100644 index 0000000..d4f9762 --- /dev/null +++ b/arduino-esp32-wifi-scan-sdk/sdkconfig.defaults @@ -0,0 +1,4 @@ +CONFIG_FREERTOS_HZ=1000 +CONFIG_MBEDTLS_PSK_MODES=y +CONFIG_MBEDTLS_KEY_EXCHANGE_PSK=y +CONFIG_AUTOSTART_ARDUINO=y