├── resources └── cmake_project │ ├── main.c │ └── CMakeLists.txt ├── .gitignore ├── .github ├── configs │ └── sdkconfig.defaults └── workflows │ ├── publish-dry-run.yml │ ├── publish.yml │ └── ci.yml ├── src ├── panic.rs ├── patches │ ├── lstat.rs │ └── pthread_rwlock.rs ├── alloc.rs ├── patches.rs ├── include │ ├── esp-8266-rtos-sdk │ │ └── bindings.h │ └── esp-idf │ │ └── bindings.h ├── error.rs ├── start.rs └── lib.rs ├── LICENSE-MIT ├── Cargo.toml ├── patches ├── missing_riscv_atomics_fix.diff ├── missing_xtensa_atomics_fix.diff └── pthread_destructor_fix.diff ├── LICENSE-APACHE └── README.md /resources/cmake_project/main.c: -------------------------------------------------------------------------------- 1 | void app_main() {} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.vscode 2 | /.espressif 3 | /.embuild 4 | /target 5 | /Cargo.lock 6 | **/*.rs.bk 7 | -------------------------------------------------------------------------------- /.github/configs/sdkconfig.defaults: -------------------------------------------------------------------------------- 1 | # Workaround for https://github.com/espressif/esp-idf/issues/7631 2 | CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=n 3 | CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=n 4 | -------------------------------------------------------------------------------- /src/panic.rs: -------------------------------------------------------------------------------- 1 | #![cfg(all(not(feature = "std"), feature = "panic_handler"))] 2 | 3 | #[cfg_attr(not(feature = "std"), panic_handler)] 4 | #[allow(dead_code)] 5 | fn panic(_info: &core::panic::PanicInfo) -> ! { 6 | unsafe { 7 | crate::abort(); 8 | core::hint::unreachable_unchecked(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/patches/lstat.rs: -------------------------------------------------------------------------------- 1 | use crate::*; 2 | 3 | static mut __LSTAT_INTERNAL_REFERENCE: *mut c_types::c_void = lstat as *mut _; 4 | 5 | pub fn link_patches() -> *mut c_types::c_void { 6 | unsafe { __LSTAT_INTERNAL_REFERENCE } 7 | } 8 | 9 | #[no_mangle] 10 | #[inline(never)] 11 | pub unsafe extern "C" fn lstat(path: *const c_types::c_char, buf: *mut stat) -> c_types::c_int { 12 | stat(path, buf) 13 | } 14 | -------------------------------------------------------------------------------- /resources/cmake_project/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20) 2 | 3 | include($ENV{IDF_PATH}/tools/cmake/idf.cmake) 4 | project(libespidf C) 5 | 6 | idf_build_process($ENV{IDF_TARGET} SDKCONFIG $ENV{SDKCONFIG} SDKCONFIG_DEFAULTS $ENV{SDKCONFIG_DEFAULTS}) 7 | idf_build_get_property(aliases BUILD_COMPONENT_ALIASES) 8 | 9 | add_executable(libespidf.elf main.c) 10 | target_link_libraries(libespidf.elf PUBLIC "${aliases}") 11 | idf_build_executable(libespidf.elf) -------------------------------------------------------------------------------- /.github/workflows/publish-dry-run.yml: -------------------------------------------------------------------------------- 1 | name: PublishDryRun 2 | 3 | on: 4 | workflow_dispatch 5 | 6 | jobs: 7 | publishdryrun: 8 | name: Publish Dry Run 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Setup | Checkout 12 | uses: actions/checkout@v2 13 | - name: Setup | Rust 14 | uses: actions-rs/toolchain@v1 15 | with: 16 | toolchain: nightly 17 | - name: Setup | Std 18 | run: rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu 19 | - name: Setup | Default to nightly 20 | run: rustup default nightly 21 | - name: Build | Publish Dry Run 22 | run: export ESP_IDF_TOOLS_INSTALL_DIR=out; export ESP_IDF_SDKCONFIG_DEFAULTS=$(pwd)/.github/configs/sdkconfig.defaults; cargo publish --dry-run --target riscv32imc-esp-espidf -Zbuild-std=std,panic_abort -Zbuild-std-features=panic_immediate_abort 23 | -------------------------------------------------------------------------------- /src/alloc.rs: -------------------------------------------------------------------------------- 1 | #![cfg(all(not(feature = "std"), feature = "alloc_handler"))] 2 | 3 | use core::alloc::{GlobalAlloc, Layout}; 4 | 5 | use crate::*; 6 | 7 | #[cfg_attr(not(feature = "std"), global_allocator)] 8 | #[allow(dead_code)] 9 | static HEAP: Esp32Alloc = Esp32Alloc; 10 | 11 | #[cfg_attr(not(feature = "std"), alloc_error_handler)] 12 | #[allow(dead_code)] 13 | fn on_oom(_layout: Layout) -> ! { 14 | unsafe { 15 | crate::abort(); 16 | core::hint::unreachable_unchecked(); 17 | } 18 | } 19 | 20 | struct Esp32Alloc; 21 | 22 | unsafe impl Sync for Esp32Alloc {} 23 | 24 | unsafe impl GlobalAlloc for Esp32Alloc { 25 | unsafe fn alloc(&self, layout: Layout) -> *mut u8 { 26 | heap_caps_malloc(layout.size() as u32, MALLOC_CAP_8BIT as _) as *mut _ 27 | } 28 | 29 | unsafe fn realloc(&self, ptr: *mut u8, _layout: Layout, new_size: usize) -> *mut u8 { 30 | heap_caps_realloc(ptr as *mut _, new_size as u32, MALLOC_CAP_8BIT as _) as *mut _ 31 | } 32 | 33 | unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { 34 | heap_caps_free(ptr as *mut _); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright 2019-2020 Contributors to xtensa-lx6-rt 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /src/patches.rs: -------------------------------------------------------------------------------- 1 | // (Temporary code) ESP-IDF does not (yet) have a pthread rwlock implementation, which is required by STD 2 | // We provide a quick and very hacky implementation here 3 | #[cfg(all(feature = "std", esp_idf_version = "4.3"))] 4 | mod pthread_rwlock; 5 | 6 | #[cfg(feature = "std")] 7 | mod lstat; 8 | 9 | pub struct PatchesRef(*mut crate::c_types::c_void, *mut crate::c_types::c_void); 10 | 11 | /// A hack to make sure that the rwlock implementation is linked to the final executable 12 | /// Call this function once e.g. in the beginning of your main function 13 | /// 14 | /// This function will become no-op once ESP-IDF V4.4 is released 15 | pub fn link_patches() -> PatchesRef { 16 | #[cfg(all(feature = "std", esp_idf_version = "4.3"))] 17 | let rwlock = pthread_rwlock::link_patches(); 18 | 19 | #[cfg(any( 20 | not(feature = "std"), 21 | not(all(feature = "std", esp_idf_version = "4.3")) 22 | ))] 23 | let rwlock = core::ptr::null_mut(); 24 | 25 | #[cfg(feature = "std")] 26 | let lstat = lstat::link_patches(); 27 | #[cfg(not(feature = "std"))] 28 | let lstat = core::ptr::null_mut(); 29 | 30 | PatchesRef(rwlock, lstat) 31 | } 32 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "esp-idf-sys" 3 | version = "0.30.6" 4 | authors = ["Alexey Arbuzov ", "sapir ", "Ivan Markov "] 5 | edition = "2021" 6 | resolver = "2" 7 | categories = ["embedded", "hardware-support"] 8 | keywords = ["sys", "idf", "esp-idf", "esp32"] 9 | description = "Bindings for ESP-IDF (Espressif's IoT Development Framework)" 10 | repository = "https://github.com/esp-rs/esp-idf-sys" 11 | license = "MIT OR Apache-2.0" 12 | readme = "README.md" 13 | links = "esp_idf" 14 | build = "build/build.rs" 15 | documentation = "https://esp-rs.github.io/esp-idf-sys/" 16 | 17 | [features] 18 | default = ["std", "pio"] 19 | 20 | std = [] 21 | alloc_handler = [] 22 | panic_handler = [] 23 | binstart = [] 24 | libstart = [] 25 | 26 | # Use `platformio` to build the `esp-idf` 27 | pio = ["embuild/pio"] 28 | # Experimental: Use native `esp-idf` tooling to build it 29 | native = ["embuild/cmake", "embuild/espidf", "strum"] 30 | 31 | [dependencies] 32 | paste = "1" 33 | 34 | [build-dependencies] 35 | embuild = { version = "0.28.4", features = ["glob"] } 36 | anyhow = "1" 37 | strum = { version = "0.23", features = ["derive"], optional = true } 38 | regex = "1.5" 39 | bindgen = "0.59" 40 | -------------------------------------------------------------------------------- /src/include/esp-8266-rtos-sdk/bindings.h: -------------------------------------------------------------------------------- 1 | // TODO: Figure out how to enable the includes below without bringing in the mess tcpip_adapter.h causes 2 | 3 | #include "esp_system.h" 4 | 5 | #include "esp_aio.h" 6 | #include "esp_attr.h" 7 | #include "esp_clk.h" 8 | #include "esp_interface.h" 9 | #include "esp_libc.h" 10 | #include "esp_netif.h" 11 | #include "esp_now.h" 12 | #include "esp_phy_init.h" 13 | #include "esp_sleep.h" 14 | #include "esp_smartconfig.h" 15 | #include "esp_ssc.h" 16 | #include "esp_task_wdt.h" 17 | #include "esp_timer.h" 18 | #include "esp_types.h" 19 | 20 | //#include "esp_event_loop.h" 21 | //#include "esp_event.h" 22 | 23 | //#include "esp_wifi.h" 24 | 25 | //#include "apps/ping/ping_sock.h" 26 | 27 | //#include "esp_http_server.h" 28 | 29 | #include "nvs.h" 30 | #include "nvs_flash.h" 31 | 32 | #include "driver/adc.h" 33 | #include "driver/gpio.h" 34 | //#include "driver/hspi_logic_layer.h" 35 | #include "driver/hw_timer.h" 36 | #include "driver/i2c.h" 37 | #include "driver/i2s.h" 38 | #include "driver/ir_rx.h" 39 | #include "driver/ir_tx.h" 40 | #include "driver/ledc.h" 41 | #include "driver/pwm.h" 42 | #include "driver/rtc.h" 43 | #include "driver/soc.h" 44 | #include "driver/spi.h" 45 | #include "driver/uart.h" 46 | #include "driver/uart_select.h" 47 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | workflow_dispatch 5 | 6 | jobs: 7 | publish: 8 | name: Publish 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Setup | Checkout 12 | uses: actions/checkout@v2 13 | - name: Setup | Rust 14 | uses: actions-rs/toolchain@v1 15 | with: 16 | toolchain: nightly 17 | - name: Setup | Std 18 | run: rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu 19 | - name: Setup | Default to nightly 20 | run: rustup default nightly 21 | - name: Setup | Default to nightly 22 | run: rustup default nightly 23 | - name: Login 24 | run: cargo login ${{ secrets.crates_io_token }} 25 | - name: Build | Publish 26 | run: export ESP_IDF_TOOLS_INSTALL_DIR=out; export ESP_IDF_SDKCONFIG_DEFAULTS=$(pwd)/.github/configs/sdkconfig.defaults; cargo publish --target riscv32imc-esp-espidf -Zbuild-std=std,panic_abort -Zbuild-std-features=panic_immediate_abort 27 | - name: Build Documentation 28 | run: cargo doc --features native --target riscv32imc-esp-espidf -Zbuild-std=std,panic_abort -Zbuild-std-features=panic_immediate_abort; echo "" > target/riscv32imc-esp-espidf/doc/index.html; mv target/riscv32imc-esp-espidf/doc ./docs 29 | - name: Deploy Documentation 30 | if: ${{ github.ref == 'refs/heads/master' }} 31 | uses: peaceiris/actions-gh-pages@v3 32 | with: 33 | github_token: ${{ secrets.GITHUB_TOKEN }} 34 | force_orphan: true 35 | publish_dir: ./docs -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | schedule: 9 | - cron: '50 4 * * *' 10 | 11 | jobs: 12 | compile: 13 | name: Compile 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Setup | Checkout 17 | uses: actions/checkout@v2 18 | - name: Setup | Rust 19 | uses: actions-rs/toolchain@v1 20 | with: 21 | toolchain: nightly 22 | components: rustfmt, clippy 23 | - name: Setup | Std 24 | run: rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu 25 | - name: Setup | Default to nightly 26 | run: rustup default nightly 27 | - name: Build | Fmt Check 28 | run: cargo fmt -- --check 29 | - name: Build | Clippy 30 | run: export ESP_IDF_SDKCONFIG_DEFAULTS=$(pwd)/.github/configs/sdkconfig.defaults; cargo clippy --no-deps --target riscv32imc-esp-espidf -Zbuild-std=std,panic_abort -Zbuild-std-features=panic_immediate_abort -- -Dwarnings 31 | # - name: Build | Compile 32 | # run: export ESP_IDF_SDKCONFIG_DEFAULTS=$(pwd)/.github/configs/sdkconfig.defaults; cargo build --target riscv32imc-esp-espidf -Zbuild-std=std,panic_abort -Zbuild-std-features=panic_immediate_abort 33 | - name: Build | Compile Native / ESP-IDF master 34 | run: cargo build --features native --target riscv32imc-esp-espidf -Zbuild-std=std,panic_abort -Zbuild-std-features=panic_immediate_abort 35 | # - name: Build | Compile Native 36 | # run: export ESP_IDF_SDKCONFIG_DEFAULTS=$(pwd)/.github/configs/sdkconfig.defaults; cargo build --features native --target riscv32imc-esp-espidf -Zbuild-std=std,panic_abort -Zbuild-std-features=panic_immediate_abort 37 | -------------------------------------------------------------------------------- /patches/missing_riscv_atomics_fix.diff: -------------------------------------------------------------------------------- 1 | diff --git a/components/riscv/stdatomic.c b/components/riscv/stdatomic.c 2 | index 9cae8ee518..015fb8fc01 100644 3 | --- a/components/riscv/stdatomic.c 4 | +++ b/components/riscv/stdatomic.c 5 | @@ -37,6 +37,21 @@ 6 | portEXIT_CRITICAL_NESTED(state); \ 7 | } while (0) 8 | 9 | +#define ATOMIC_LOAD(n, type) type __atomic_load_ ## n (const type* mem, int memorder) \ 10 | +{ \ 11 | + unsigned state = _ATOMIC_ENTER_CRITICAL(); \ 12 | + type ret = *mem; \ 13 | + _ATOMIC_EXIT_CRITICAL(state); \ 14 | + return ret; \ 15 | +} 16 | + 17 | +#define ATOMIC_STORE(n, type) void __atomic_store_ ## n (type* mem, type val, int memorder) \ 18 | +{ \ 19 | + unsigned state = _ATOMIC_ENTER_CRITICAL(); \ 20 | + *mem = val; \ 21 | + _ATOMIC_EXIT_CRITICAL(state); \ 22 | +} 23 | + 24 | #define ATOMIC_EXCHANGE(n, type) type __atomic_exchange_ ## n (type* mem, type val, int memorder) \ 25 | { \ 26 | unsigned state = _ATOMIC_ENTER_CRITICAL(); \ 27 | @@ -141,6 +156,16 @@ 28 | 29 | #pragma GCC diagnostic ignored "-Wbuiltin-declaration-mismatch" 30 | 31 | +ATOMIC_LOAD(1, uint8_t) 32 | +ATOMIC_LOAD(2, uint16_t) 33 | +ATOMIC_LOAD(4, uint32_t) 34 | +ATOMIC_LOAD(8, uint64_t) 35 | + 36 | +ATOMIC_STORE(1, uint8_t) 37 | +ATOMIC_STORE(2, uint16_t) 38 | +ATOMIC_STORE(4, uint32_t) 39 | +ATOMIC_STORE(8, uint64_t) 40 | + 41 | ATOMIC_EXCHANGE(1, uint8_t) 42 | ATOMIC_EXCHANGE(2, uint16_t) 43 | ATOMIC_EXCHANGE(4, uint32_t) 44 | -------------------------------------------------------------------------------- /patches/missing_xtensa_atomics_fix.diff: -------------------------------------------------------------------------------- 1 | diff --git a/components/xtensa/stdatomic.c b/components/xtensa/stdatomic.c 2 | index 4dc425c50..84e3ccbb1 100644 3 | --- a/components/xtensa/stdatomic.c 4 | +++ b/components/xtensa/stdatomic.c 5 | @@ -133,6 +133,22 @@ 6 | return ret; \ 7 | } 8 | 9 | +#define SYNC_LOCK_TEST_AND_SET(n, type) type __sync_lock_test_and_set_ ## n (type *ptr, type val, ...) \ 10 | +{ \ 11 | + unsigned state = _ATOMIC_ENTER_CRITICAL(); \ 12 | + type ret = *ptr; \ 13 | + *ptr = val; \ 14 | + _ATOMIC_EXIT_CRITICAL(state); \ 15 | + return ret; \ 16 | +} 17 | + 18 | +#define SYNC_LOCK_RELEASE(n, type) void __sync_lock_release_ ## n (type *ptr, ...) \ 19 | +{ \ 20 | + unsigned state = _ATOMIC_ENTER_CRITICAL(); \ 21 | + *ptr = 0; \ 22 | + _ATOMIC_EXIT_CRITICAL(state); \ 23 | +} 24 | + 25 | #ifndef XCHAL_HAVE_S32C1I 26 | #error "XCHAL_HAVE_S32C1I not defined, include correct header!" 27 | #endif 28 | @@ -212,4 +228,14 @@ SYNC_VAL_CMP_EXCHANGE(2, uint16_t) 29 | SYNC_VAL_CMP_EXCHANGE(4, uint32_t) 30 | SYNC_VAL_CMP_EXCHANGE(8, uint64_t) 31 | 32 | +SYNC_LOCK_TEST_AND_SET(1, uint8_t) 33 | +SYNC_LOCK_TEST_AND_SET(2, uint16_t) 34 | +SYNC_LOCK_TEST_AND_SET(4, uint32_t) 35 | +SYNC_LOCK_TEST_AND_SET(8, uint64_t) 36 | + 37 | +SYNC_LOCK_RELEASE(1, uint8_t) 38 | +SYNC_LOCK_RELEASE(2, uint16_t) 39 | +SYNC_LOCK_RELEASE(4, uint32_t) 40 | +SYNC_LOCK_RELEASE(8, uint64_t) 41 | + 42 | #endif 43 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_upper_case_globals)] 2 | #![allow(non_camel_case_types)] 3 | #![allow(non_snake_case)] 4 | 5 | use core::{fmt, slice, str}; 6 | 7 | use crate::*; 8 | 9 | #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] 10 | pub struct EspError(esp_err_t); 11 | 12 | impl EspError { 13 | pub fn from(error: esp_err_t) -> Option { 14 | if error == 0 { 15 | None 16 | } else { 17 | Some(EspError(error)) 18 | } 19 | } 20 | 21 | pub fn check_and_return(error: esp_err_t, value: T) -> Result { 22 | if error == 0 { 23 | Ok(value) 24 | } else { 25 | Err(EspError(error)) 26 | } 27 | } 28 | 29 | pub fn convert(error: esp_err_t) -> Result<(), Self> { 30 | EspError::check_and_return(error, ()) 31 | } 32 | 33 | pub fn panic(&self) { 34 | panic!("ESP-IDF ERROR: {}", self); 35 | } 36 | 37 | pub fn code(&self) -> esp_err_t { 38 | self.0 39 | } 40 | } 41 | 42 | #[cfg(feature = "std")] 43 | impl std::error::Error for EspError {} 44 | 45 | impl fmt::Display for EspError { 46 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 47 | unsafe fn strlen(c_s: *const c_types::c_char) -> usize { 48 | let mut len = 0; 49 | while *c_s.offset(len) != 0 { 50 | len += 1; 51 | } 52 | 53 | len as usize 54 | } 55 | 56 | unsafe { 57 | let c_s = esp_err_to_name(self.code()); 58 | str::from_utf8_unchecked(slice::from_raw_parts(c_s as *const u8, strlen(c_s))).fmt(f) 59 | } 60 | } 61 | } 62 | 63 | #[macro_export] 64 | macro_rules! esp { 65 | ($err:expr) => {{ 66 | esp_idf_sys::EspError::convert($err as esp_idf_sys::esp_err_t) 67 | }}; 68 | } 69 | 70 | #[macro_export] 71 | macro_rules! esp_result { 72 | ($err:expr, $value:expr) => {{ 73 | esp_idf_sys::EspError::check_and_return($err as esp_idf_sys::esp_err_t, $value) 74 | }}; 75 | } 76 | 77 | #[macro_export] 78 | macro_rules! esp_nofail { 79 | ($err:expr) => {{ 80 | if let Some(error) = esp_idf_sys::EspError::from($err as esp_idf_sys::esp_err_t) { 81 | error.panic(); 82 | } 83 | }}; 84 | } 85 | -------------------------------------------------------------------------------- /src/patches/pthread_rwlock.rs: -------------------------------------------------------------------------------- 1 | // TODO: This is __wrong__ and needs to be replaced with a proper implementation e.g. in the spirit of this: 2 | // https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock#Using_a_condition_variable_and_a_mutex 3 | 4 | use crate::*; 5 | 6 | static mut __PTHREAD_RWLOCK_INTERNAL_REFERENCE: *mut c_types::c_void = 7 | pthread_rwlock_init as *mut _; 8 | 9 | pub fn link_patches() -> *mut c_types::c_void { 10 | unsafe { __PTHREAD_RWLOCK_INTERNAL_REFERENCE } 11 | } 12 | 13 | #[no_mangle] 14 | #[inline(never)] 15 | pub unsafe extern "C" fn pthread_rwlock_init( 16 | rwlock: *mut c_types::c_void, 17 | attr: *const c_types::c_void, 18 | ) -> c_types::c_int { 19 | pthread_mutex_init(rwlock as *mut _, attr as *const _) 20 | } 21 | 22 | #[no_mangle] 23 | #[inline(never)] 24 | pub unsafe extern "C" fn pthread_rwlock_rdlock(rwlock: *mut c_types::c_void) -> c_types::c_int { 25 | pthread_mutex_lock(rwlock as *mut _) 26 | } 27 | 28 | #[no_mangle] 29 | #[inline(never)] 30 | pub unsafe extern "C" fn pthread_rwlock_tryrdlock(rwlock: *mut c_types::c_void) -> c_types::c_int { 31 | pthread_mutex_trylock(rwlock as *mut _) 32 | } 33 | 34 | #[no_mangle] 35 | #[inline(never)] 36 | pub unsafe extern "C" fn pthread_rwlock_wrlock(rwlock: *mut c_types::c_void) -> c_types::c_int { 37 | pthread_mutex_lock(rwlock as *mut _) 38 | } 39 | 40 | #[no_mangle] 41 | #[inline(never)] 42 | pub unsafe extern "C" fn pthread_rwlock_trywrlock(rwlock: *mut c_types::c_void) -> c_types::c_int { 43 | pthread_mutex_trylock(rwlock as *mut _) 44 | } 45 | 46 | #[no_mangle] 47 | #[inline(never)] 48 | pub unsafe extern "C" fn pthread_rwlock_unlock(rwlock: *mut c_types::c_void) -> c_types::c_int { 49 | pthread_mutex_unlock(rwlock as *mut _) 50 | } 51 | 52 | #[no_mangle] 53 | #[inline(never)] 54 | pub unsafe extern "C" fn pthread_rwlock_destroy(rwlock: *mut c_types::c_void) -> c_types::c_int { 55 | pthread_mutex_destroy(rwlock as *mut _) 56 | } 57 | 58 | #[no_mangle] 59 | #[inline(never)] 60 | pub unsafe extern "C" fn pthread_rwlockattr_init(attr: *mut c_types::c_void) -> c_types::c_int { 61 | pthread_mutexattr_init(attr as *mut _) 62 | } 63 | 64 | #[no_mangle] 65 | #[inline(never)] 66 | pub unsafe extern "C" fn pthread_rwlockattr_destroy(attr: *mut c_types::c_void) -> c_types::c_int { 67 | pthread_rwlockattr_init(attr as *mut _) 68 | } 69 | -------------------------------------------------------------------------------- /src/start.rs: -------------------------------------------------------------------------------- 1 | #![cfg(any(feature = "binstart", feature = "libstart"))] 2 | 3 | #[cfg(all(feature = "binstart", feature = "libstart"))] 4 | compile_error!("Features `binstart` and `libstart` are mutually exclusive."); 5 | 6 | /// When compiling a binary Rust crate in STD (e.g. in Cargo-first builds) and NOT doing 7 | /// any tricks like using #[no_main] or #[start], the Rust compiler will autogenerate 8 | /// a C function with the signature as below which will be proxying 9 | /// the real Rust main function of your binary crate 10 | /// 11 | /// So to bridge this function with the real C "app_main()" entrypoint 12 | /// that ESP-IDF expects it is enough to implement app_main() and call in it 13 | /// the "main" C function autogenerated by the Rust compiler 14 | /// 15 | /// See https://github.com/rust-lang/rust/issues/29633 for more information 16 | #[cfg(all(feature = "std", feature = "binstart"))] 17 | extern "C" { 18 | fn main(p1: isize, p2: *const *const u8) -> isize; 19 | } 20 | 21 | /// When compiling a static Rust library crate (e.g. by using a PIO->Cargo or a CMake->Cargo) build, 22 | /// there is no main function that the Rust compiler expects, nor autogeneration of a callable 23 | /// wrapper around it. 24 | /// 25 | /// In that case (and if the "libstart" feature is enabled), it is _us_ (not the Rust compiler) 26 | /// expecting the user to define a rust #[no_mangle] "main" function and it is our code below which is explicitly 27 | /// calling it from app_main(). If the user does not define a main() runction in Rust, there will 28 | /// be a linkage error instead of the nice Rust syntax error for binary crates. 29 | /// 30 | /// Another restriction of the "libstart" feature is that the Rust main function will always have one 31 | /// fixed signature: "fn main() -> ()" - as opposed to the flexibility of main() in binary crates 32 | /// where it can have quite a few different returning types 33 | /// 34 | /// When compiling a binary Rust crate in no_std, we end up in identical situation: 35 | /// - There is no Rust "lang = start" item defined 36 | /// - As such, there is no magic C "main" function defined for, which would proxy our binary crate main 37 | #[cfg(any(all(not(feature = "std"), feature = "binstart"), feature = "libstart"))] 38 | extern "Rust" { 39 | fn main(); 40 | } 41 | 42 | #[no_mangle] 43 | pub extern "C" fn app_main() { 44 | unsafe { 45 | #[cfg(all(feature = "std", feature = "binstart"))] 46 | main(0, &[core::ptr::null()] as *const *const u8); 47 | 48 | #[cfg(any(all(not(feature = "std"), feature = "binstart"), feature = "libstart"))] 49 | main(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | #![cfg_attr( 3 | all(not(feature = "std"), feature = "alloc_handler"), 4 | feature(alloc_error_handler) 5 | )] 6 | 7 | pub use bindings::*; 8 | pub use error::*; 9 | pub use patches::PatchesRef; 10 | 11 | mod alloc; 12 | mod error; 13 | mod panic; 14 | mod patches; 15 | mod start; 16 | 17 | /// A hack to make sure that the rwlock implementation and the esp32c3 atomics are linked to the final executable 18 | /// Call this function once e.g. in the beginning of your main function 19 | /// 20 | /// This function will become no-op once ESP-IDF V4.4 is released 21 | pub fn link_patches() -> PatchesRef { 22 | patches::link_patches() 23 | } 24 | 25 | #[cfg(feature = "std")] 26 | #[allow(non_upper_case_globals)] 27 | #[allow(non_camel_case_types)] 28 | pub mod c_types { 29 | pub type c_void = std::os::raw::c_void; 30 | pub type c_uchar = std::os::raw::c_uchar; 31 | pub type c_schar = std::os::raw::c_schar; 32 | pub type c_char = std::os::raw::c_char; 33 | pub type c_short = std::os::raw::c_short; 34 | pub type c_ushort = std::os::raw::c_ushort; 35 | pub type c_int = std::os::raw::c_int; 36 | pub type c_uint = std::os::raw::c_uint; 37 | pub type c_long = std::os::raw::c_long; 38 | pub type c_ulong = std::os::raw::c_ulong; 39 | pub type c_longlong = std::os::raw::c_longlong; 40 | pub type c_ulonglong = std::os::raw::c_ulonglong; 41 | } 42 | 43 | #[cfg(not(feature = "std"))] 44 | #[allow(non_upper_case_globals)] 45 | #[allow(non_camel_case_types)] 46 | pub mod c_types { 47 | pub type c_void = core::ffi::c_void; 48 | pub type c_uchar = u8; 49 | pub type c_schar = i8; 50 | // Even though libc and STD do use a signed char type for both RiscV & Xtensa, 51 | // we need to switch to unsigned char for no_std + RiscV in order to match what 52 | // is currently hard-coded in the cty crate (used by the CStr & CString impls in no_std): 53 | // https://github.com/japaric/cty/blob/master/src/lib.rs#L30 54 | #[cfg(target_arch = "riscv32")] 55 | pub type c_char = u8; 56 | #[cfg(not(target_arch = "riscv32"))] 57 | pub type c_char = i8; 58 | pub type c_short = i16; 59 | pub type c_ushort = u16; 60 | pub type c_int = i32; 61 | pub type c_uint = u32; 62 | pub type c_long = i32; 63 | pub type c_ulong = u32; 64 | pub type c_longlong = i64; 65 | pub type c_ulonglong = u64; 66 | } 67 | 68 | #[allow(clippy::all)] 69 | #[allow(non_upper_case_globals)] 70 | #[allow(non_camel_case_types)] 71 | #[allow(non_snake_case)] 72 | #[allow(improper_ctypes)] // TODO: For now, as 5.0 spits out tons of these 73 | mod bindings { 74 | use super::c_types; 75 | 76 | include!(env!("EMBUILD_GENERATED_BINDINGS_FILE")); 77 | } 78 | -------------------------------------------------------------------------------- /patches/pthread_destructor_fix.diff: -------------------------------------------------------------------------------- 1 | diff --git a/components/pthread/pthread_local_storage.c b/components/pthread/pthread_local_storage.c 2 | index 557276847..e784c4cb6 100644 3 | --- a/components/pthread/pthread_local_storage.c 4 | +++ b/components/pthread/pthread_local_storage.c 5 | @@ -113,12 +113,17 @@ int pthread_key_delete(pthread_key_t key) 6 | This is called from one of two places: 7 | 8 | If the thread was created via pthread_create() then it's called by pthread_task_func() when that thread ends, 9 | - and the FreeRTOS thread-local-storage is removed before the FreeRTOS task is deleted. 10 | + or calls pthread_exit(), and the FreeRTOS thread-local-storage is removed before the FreeRTOS task is deleted. 11 | 12 | For other tasks, this is called when the FreeRTOS idle task performs its task cleanup after the task is deleted. 13 | 14 | - (The reason for calling it early for pthreads is to keep the timing consistent with "normal" pthreads, so after 15 | - pthread_join() the task's destructors have all been called even if the idle task hasn't run cleanup yet.) 16 | + There are two reasons for calling it early for pthreads: 17 | + 18 | + - To keep the timing consistent with "normal" pthreads, so after pthread_join() the task's destructors have all 19 | + been called even if the idle task hasn't run cleanup yet. 20 | + 21 | + - The destructor is always called in the context of the thread itself - which is important if the task then calls 22 | + pthread_getspecific() or pthread_setspecific() to update the state further, as allowed for in the spec. 23 | */ 24 | static void pthread_local_storage_thread_deleted_callback(int index, void *v_tls) 25 | { 26 | @@ -126,8 +131,13 @@ static void pthread_local_storage_thread_deleted_callback(int index, void *v_tls 27 | assert(tls != NULL); 28 | 29 | /* Walk the list, freeing all entries and calling destructors if they are registered */ 30 | - value_entry_t *entry = SLIST_FIRST(tls); 31 | - while(entry != NULL) { 32 | + while (1) { 33 | + value_entry_t *entry = SLIST_FIRST(tls); 34 | + if (entry == NULL) { 35 | + break; 36 | + } 37 | + SLIST_REMOVE_HEAD(tls, next); 38 | + 39 | // This is a little slow, walking the linked list of keys once per value, 40 | // but assumes that the thread's value list will have less entries 41 | // than the keys list 42 | @@ -135,9 +145,7 @@ static void pthread_local_storage_thread_deleted_callback(int index, void *v_tls 43 | if (key != NULL && key->destructor != NULL) { 44 | key->destructor(entry->value); 45 | } 46 | - value_entry_t *next_entry = SLIST_NEXT(entry, next); 47 | free(entry); 48 | - entry = next_entry; 49 | } 50 | free(tls); 51 | } 52 | @@ -250,7 +258,22 @@ int pthread_setspecific(pthread_key_t key, const void *value) 53 | } 54 | entry->key = key; 55 | entry->value = (void *) value; // see note above about cast 56 | - SLIST_INSERT_HEAD(tls, entry, next); 57 | + 58 | + // insert the new entry at the end of the list. this is important because 59 | + // a destructor may call pthread_setspecific() to add a new non-NULL value 60 | + // to the list, and this should be processed after all other entries. 61 | + // 62 | + // See pthread_local_storage_thread_deleted_callback() 63 | + value_entry_t *last_entry = NULL; 64 | + value_entry_t *it; 65 | + SLIST_FOREACH(it, tls, next) { 66 | + last_entry = it; 67 | + } 68 | + if (last_entry == NULL) { 69 | + SLIST_INSERT_HEAD(tls, entry, next); 70 | + } else { 71 | + SLIST_INSERT_AFTER(last_entry, entry, next); 72 | + } 73 | } 74 | 75 | return 0; 76 | -------------------------------------------------------------------------------- /src/include/esp-idf/bindings.h: -------------------------------------------------------------------------------- 1 | #include "esp_system.h" 2 | 3 | #if ((ESP_IDF_VERSION_MAJOR < 4) || ((ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR < 3)) || ((ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR == 3) && (ESP_IDF_VERSION_PATCH < 2))) 4 | #error Only ESP-IDF versions >= V4.3.2 are currently supported; if you are using the PIO build (the default one), wipe out your `.embuild` folder and try again with a clean rebuild 5 | #endif 6 | 7 | //#include "esp_crc.h" 8 | #include "esp_log.h" 9 | #include "esp_debug_helpers.h" 10 | 11 | #include "esp_sleep.h" 12 | #include "esp_task.h" 13 | #include "esp_task_wdt.h" 14 | #include "esp_int_wdt.h" 15 | #include "esp_interface.h" 16 | #include "esp_ipc.h" 17 | 18 | #ifdef ESP_IDF_COMP_ESP_PM_ENABLED 19 | #include "esp_pm.h" 20 | #endif 21 | 22 | #ifdef ESP_IDF_COMP_ESP_TIMER_ENABLED 23 | #include "esp_timer.h" 24 | #endif 25 | 26 | #ifdef ESP_IDF_COMP_SPI_FLASH_ENABLED 27 | #include "esp_spi_flash.h" 28 | #include "esp_partition.h" 29 | #endif 30 | 31 | #ifdef ESP_IDF_COMP_ESP_ADC_CAL_ENABLED 32 | #include "esp_adc_cal.h" 33 | #endif 34 | 35 | #ifdef ESP_IDF_COMP_ESP_EVENT_ENABLED 36 | #include "esp_event.h" 37 | #endif 38 | 39 | #ifdef ESP_IDF_COMP_ESP_NETIF_ENABLED 40 | #include "esp_netif.h" 41 | #endif 42 | 43 | #ifdef ESP_IDF_COMP_ESP_WIFI_ENABLED 44 | #include "esp_wifi.h" 45 | #ifdef ESP_IDF_COMP_ESP_NETIF_ENABLED 46 | #include "esp_wifi_netif.h" 47 | #endif 48 | #endif 49 | 50 | #ifdef ESP_IDF_COMP_ESP_ETH_ENABLED 51 | #include "esp_eth.h" 52 | #ifdef ESP_IDF_COMP_ESP_NETIF_ENABLED 53 | #include "esp_eth_netif_glue.h" 54 | #endif 55 | #endif 56 | 57 | #ifdef ESP_IDF_COMP_VFS_ENABLED 58 | #include "esp_vfs.h" 59 | #include "esp_vfs_cdcacm.h" 60 | #include "esp_vfs_dev.h" 61 | #include "esp_vfs_semihost.h" 62 | #include "esp_vfs_usb_serial_jtag.h" 63 | 64 | #if ((ESP_IDF_VERSION_MAJOR > 4) || ((ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 4))) 65 | #include "esp_vfs_console.h" 66 | #endif 67 | 68 | #if ((ESP_IDF_VERSION_MAJOR > 4) || ((ESP_IDF_VERSION_MAJOR == 4) && (ESP_IDF_VERSION_MINOR >= 4))) 69 | #include "esp_vfs_eventfd.h" 70 | #endif 71 | 72 | #ifdef ESP_IDF_COMP_SPIFFS_ENABLED 73 | #include "esp_spiffs.h" 74 | #endif 75 | 76 | #ifdef ESP_IDF_COMP_FATFS_ENABLED 77 | #include "esp_vfs_fat.h" 78 | #endif 79 | 80 | #endif 81 | 82 | #include "lwip/lwip_napt.h" 83 | #include "esp_sntp.h" 84 | 85 | #include "ping/ping_sock.h" 86 | 87 | #ifdef ESP_IDF_COMP_ESP_TLS_ENABLED 88 | #include "esp_tls.h" 89 | 90 | #ifdef CONFIG_ESP_TLS_USING_MBEDTLS 91 | #include "esp_crt_bundle.h" 92 | #endif 93 | #endif 94 | 95 | #ifdef ESP_IDF_COMP_APP_UPDATE_ENABLED 96 | #include "esp_ota_ops.h" 97 | #endif 98 | 99 | #ifdef ESP_IDF_COMP_ESP_HTTP_CLIENT_ENABLED 100 | #include "esp_http_client.h" 101 | #endif 102 | 103 | #ifdef ESP_IDF_COMP_ESP_HTTP_SERVER_ENABLED 104 | #include "esp_http_server.h" 105 | #endif 106 | 107 | #ifdef ESP_IDF_COMP_MDNS_ENABLED 108 | #include "mdns.h" 109 | #endif 110 | 111 | #ifdef ESP_IDF_COMP_MQTT_ENABLED 112 | #include "mqtt_client.h" 113 | #endif 114 | 115 | #ifdef ESP_IDF_COMP_NVS_FLASH_ENABLED 116 | #include "nvs.h" 117 | #include "nvs_flash.h" 118 | #endif 119 | 120 | #ifdef ESP_IDF_COMP_ESP_WIFI_PROVISIONING_ENABLED 121 | #include "wifi_provisioning/manager.h" 122 | #include "wifi_provisioning/scheme_ble.h" 123 | #include "wifi_provisioning/scheme_softap.h" 124 | #endif 125 | 126 | #ifdef ESP_IDF_COMP_SOC_ENABLED 127 | // TODO: Include all XXX_periph.h headers here 128 | #include "soc/gpio_periph.h" 129 | #endif 130 | 131 | #include "driver/adc.h" 132 | #include "driver/twai.h" 133 | #if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) 134 | #include "driver/dac.h" 135 | #endif 136 | #include "driver/gpio.h" 137 | #include "driver/i2c.h" 138 | #include "driver/i2s.h" 139 | #include "driver/ledc.h" 140 | #include "driver/mcpwm.h" 141 | #ifndef CONFIG_IDF_TARGET_ESP32C3 142 | #include "driver/pcnt.h" 143 | #endif 144 | #include "driver/periph_ctrl.h" 145 | #include "driver/rmt.h" 146 | #include "driver/rtc_cntl.h" 147 | #include "driver/rtc_io.h" 148 | #ifdef CONFIG_IDF_TARGET_ESP32 149 | #include "driver/sdio_slave.h" 150 | #endif 151 | #include "driver/sdmmc_defs.h" 152 | #include "driver/sdmmc_host.h" 153 | #include "driver/sdmmc_types.h" 154 | #include "driver/sdspi_host.h" 155 | #include "driver/sigmadelta.h" 156 | #include "driver/spi_common.h" 157 | #include "driver/spi_master.h" 158 | #include "driver/spi_slave.h" 159 | #include "driver/timer.h" 160 | 161 | #ifndef CONFIG_IDF_TARGET_ESP32C3 162 | #include "driver/touch_pad.h" 163 | #endif 164 | 165 | #include "driver/uart.h" 166 | #include "driver/uart_select.h" 167 | 168 | #ifdef ESP_IDF_COMP_ESPCOREDUMP_ENABLED 169 | #include "esp_core_dump.h" 170 | #endif 171 | 172 | #ifdef ESP_IDF_COMP_ESP_SERIAL_SLAVE_LINK_ENABLED 173 | #include "esp_serial_slave_link/essl.h" 174 | #include "esp_serial_slave_link/essl_sdio.h" 175 | #endif 176 | 177 | #include "pthread.h" 178 | 179 | #ifdef ESP_IDF_COMP_PTHREAD_ENABLED 180 | #include "esp_pthread.h" 181 | #endif 182 | 183 | #ifdef CONFIG_ESP32_ULP_COPROC_ENABLED 184 | #include "esp32/ulp.h" 185 | #endif 186 | 187 | #ifdef CONFIG_ESP32S2_ULP_COPROC_ENABLED 188 | #ifdef CONFIG_ESP32S2_ULP_COPROC_RISCV 189 | #include "esp32s2/ulp_riscv.h" 190 | #else 191 | #include "esp32s2/ulp.h" 192 | #endif 193 | #endif 194 | 195 | #ifdef CONFIG_ESP32S3_ULP_COPROC_ENABLED 196 | #ifdef CONFIG_ESP32S3_ULP_COPROC_RISCV 197 | #include "esp32s3/ulp_riscv.h" 198 | #else 199 | #include "esp32s2/ulp.h" 200 | #endif 201 | #endif 202 | 203 | 204 | #ifndef CONFIG_IDF_TARGET_ESP32S2 // No BT in ESP32-S2 205 | 206 | // If a custom sdkconfig file has been used to enable Bluetooth support, 207 | // since by default neither of the BT stacks is enabled. 208 | #ifdef CONFIG_BT_ENABLED 209 | #include "esp_bt.h" 210 | #endif 211 | 212 | #ifdef CONFIG_BT_BLUEDROID_ENABLED 213 | #include "esp_gap_ble_api.h" 214 | #include "esp_gattc_api.h" 215 | #include "esp_gatt_defs.h" 216 | #include "esp_gatt_common_api.h" 217 | #include "esp_gatts_api.h" 218 | #include "esp_bt_defs.h" 219 | #include "esp_bt_main.h" 220 | #include "esp_gap_bt_api.h" 221 | #include "esp_bt_device.h" 222 | #endif 223 | 224 | #ifdef CONFIG_BT_NIMBLE_ENABLED 225 | #include "esp_nimble_hci.h" 226 | #include "nimble/nimble_port.h" 227 | #include "nimble/nimble_port_freertos.h" 228 | #include "host/ble_hs.h" 229 | #include "host/util/util.h" 230 | #endif 231 | 232 | #endif 233 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rust bindings for ESP-IDF (Espressif's IoT Development Framework) 2 | 3 | ## Background 4 | 5 | The ESP-IDF API in Rust, with support for each ESP chip (ESP32, ESP32S2, ESP32S3, ESP32C3 etc.) based on the Rust target. 6 | 7 | ![CI](https://github.com/esp-rs/esp-idf-sys/actions/workflows/ci.yml/badge.svg) 8 | 9 | ## Build 10 | 11 | - To build this crate, please follow all the build requirements specified in the [ESP-IDF Rust Hello World template crate](https://github.com/esp-rs/esp-idf-template) 12 | - The relevant Espressif toolchain, as well as the ESP-IDF framework itself are all automatically 13 | downloaded during the build: 14 | - With feature `pio` (default): utilizing [platformio](https://platformio.org/) (via the [embuild](https://github.com/ivmarkov/embuild) crate) or 15 | - With feature `native` (*experimental*): utilizing native `esp-idf` tooling also via the [embuild](https://github.com/ivmarkov/embuild) crate. 16 | - Check the [ESP-IDF Rust Hello World template crate](https://github.com/esp-rs/esp-idf-template) for a "Hello, world!" Rust template demonstrating how to use and build this crate. 17 | - Check the [demo](https://github.com/ivmarkov/rust-esp32-std-demo) crate for a more comprehensive example in terms of capabilities. 18 | 19 | ## Feature `pio` 20 | This is currently the default for installing all build tools and building the ESP-IDF framework. It uses [PlatformIO](https://platformio.org/) via the 21 | [embuild](https://github.com/ivmarkov/embuild) crate. 22 | 23 | The `pio` builder installs all needed tools to compile this crate as well as the ESP-IDF framework itself. 24 | 25 | ### (PIO builder only) Using cargo-pio to interactively modify ESP-IDF's `sdkconfig` file 26 | 27 | To enable Bluetooth, or do other configurations to the ESP-IDF sdkconfig you might take advantage of the cargo-pio Cargo subcommand: 28 | * To install it, issue `cargo install cargo-pio --git https://github.com/ivmarkov/cargo-pio` 29 | * To open the ESP-IDF interactive menuconfig system, issue `cargo pio espidf menuconfig` in the root of your **binary crate** project 30 | * To use the generated/updated `sdkconfig` file, follow the steps described in the "Bluetooth Support" section 31 | 32 | ## Feature `native` 33 | This is an experimental feature for downloading all tools and building the ESP-IDF framework using the framework's "native" (own) tooling. 34 | It will become the default in the near future. 35 | It also relies on build and installation utilities available in the [embuild](https://github.com/ivmarkov/embuild) crate. 36 | 37 | Similarly to the `pio` builder, the `native` builder also automatically installs all needed tools to compile this crate as well as the ESP-IDF framework itself. 38 | 39 | ### (Native builder only) Using cargo-idf to interactively modify ESP-IDF's `sdkconfig` file 40 | 41 | TBD: Upcoming 42 | 43 | ## Configuration 44 | 45 | Environment variables are used to configure how the ESP-IDF framework is compiled. 46 | 47 | Note that instead of / in addition to specifying those on the command line, you can also put these in a `.config/cargo.toml` file inside your crate directory 48 | (or a parent directory of your crate) by using the recently stabilized Cargo [configurable-env](https://doc.rust-lang.org/cargo/reference/config.html#env) feature. 49 | 50 | The following environment variables are used by the build script: 51 | 52 | - `ESP_IDF_SDKCONFIG_DEFAULTS`: 53 | 54 | A `;`-separated list of paths to `sdkconfig.defaults` files to be used as base 55 | values for the `sdkconfig`. If such a path is relative, it will be relative to the 56 | cargo workspace directory (i.e. the directory that contains the `target` dir). 57 | 58 | If unspecified `sdkconfig.defaults` is used as default. 59 | 60 | For each defaults file in this list more specific version will also be searched and 61 | used. This happens with the following patterns and order (least to most specific): 62 | 63 | 1. `` 64 | 2. `.` 65 | 3. `.` 66 | 4. `..` 67 | 68 | where `` is the current cargo profile used (`debug`/`release`) and `` 69 | specifies the mcu for which this is currently compiled for (see the `MCU` 70 | configuration option below). 71 | 72 | Also note that a setting contained in a more specific defaults file will override the 73 | same setting specified in a less specific one. 74 | 75 | - `ESP_IDF_SDKCONFIG`: 76 | 77 | The base-path to the `sdkconfig` file used to [configure the 78 | `esp-idf`](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/kconfig.html). 79 | If this is a relative path, it is relative to the cargo workspace directory. 80 | 81 | If unspecified `sdkconfig` is used as default. 82 | 83 | Similar to the `sdkconfig.defaults`-file a more specific `sdkconfig`-file will be 84 | selected if available. This happens with the following patterns and precedence: 85 | 86 | 1. `..` 87 | 2. `.` 88 | 3. `.` 89 | 4. `` 90 | 91 | **Note** (*native* builder only): 92 | The cargo optimization options (`debug` and `opt-level`) are used by default to 93 | determine the compiler optimizations of the `esp-idf`, **however** if the compiler 94 | optimization options are already set in the `sdkconfig` **they will be used instead.** 95 | 96 | 97 | - `ESP_IDF_TOOLS_INSTALL_DIR`: 98 | 99 | The location where the ESP-IDF framework tooling is assumed to be/will be installed. 100 | The framework tooling is either PlatformIO (when the `pio` builder is used), or the ESP-IDF native toolset (when the `native` builder is used). 101 | 102 | This variable can take one of the following values: 103 | - `workspace` (default) - the tooling will be installed/used in 104 | `/.embuild/platformio` for `pio`, and `/.embuild/espressif` for the `native` builder; 105 | - `out` - the tooling will be installed/used inside the crate's build output directory, and will be deleted when `cargo clean` is invoked; 106 | - `global` - the tooling will be installed/used in its standard directory (`~/.platformio` for PlatformIO, and `~./espressif` for the native ESP-IDF toolset); 107 | - `custom:` - the tooling will be installed/used in the directory specified by ``. If this directory is a relative location, it is assumed to be 108 | relative to the crate's workspace dir. 109 | 110 | **ATTENTION**: Please be extra careful with the `custom:` setting when switching from `pio` to `native` and the other way around, because 111 | the builder will install the tooling in `` without using any additional `platformio` or `espressif` subdirectories, so if you are not careful, you might end up with 112 | both PlatformIO, as well as the ESP-IDF native tooling intermingled together in a single folder. 113 | 114 | 115 | Note that both builders (`native` and `pio`) clone the ESP-IDF GIT repository *inside* the tooling directory as well. This restriction might be lifted soon for the `native` builder, whereas the user would be able to point the build to a custom ESP-IDF repository location. 116 | 117 | - `ESP_IDF_VERSION` (*native* builder only): 118 | 119 | The version used for the `esp-idf` can be one of the following: 120 | - `commit:`: Uses the commit `` of the `esp-idf` repository. 121 | Note that this will clone the whole `esp-idf` not just one commit. 122 | - `tag:`: Uses the tag `` of the `esp-idf` repository. 123 | - `branch:`: Uses the branch `` of the `esp-idf` repository. 124 | - `v.` or `.`: Uses the tag `v.` of the `esp-idf` repository. 125 | - ``: Uses the branch `` of the `esp-idf` repository. 126 | 127 | It defaults to `v4.3.1`. 128 | 129 | 130 | - `ESP_IDF_REPOSITORY` (*native* builder only): 131 | 132 | The URL to the git repository of the `esp-idf`, defaults to . 133 | 134 | Note that when the `pio` builder is used, it is possible to achieve something similar to `ESP_IDF_VERSION` and `ESP_IDF_REPOSITORY` by using 135 | the [`platform_packages`](https://docs.platformio.org/en/latest/projectconf/section_env_platform.html#platform-packages) PlatformIO option as follows: 136 | - `ESP_IDF_PIO_CONF="platform_packages = framework-espidf @ [@ ]"` 137 | - The above approach however has the restriction that PlatformIO will always use the ESP-IDF build tooling from its own ESP-IDF distribution, 138 | so the user-provided ESP-IDF branch may or may not compile. The current PlatformIO tooling is suitable for compiling ESP-IDF branches derived from versions 4.3.X . 139 | 140 | 141 | - `ESP_IDF_GLOB[_XXX]_BASE` and `ESP_IDF_GLOB[_XXX]_YYY`: 142 | 143 | A pair of environment variable prefixes that enable copying files and directory trees that match a certain glob mask into the native C project used for building the ESP-IDF framework: 144 | - `ESP_IDF_GLOB[_XXX]_BASE` specifies the base directory which will be glob-ed for resources to be copied 145 | - `ESP_IDF_GLOB[_XXX]_BASE_YYY` specifies one or more environment variables that represent the glob masks of resources to be searched for and copied, using the directory designated by the `ESP_IDF_GLOB[_XXX]_BASE` environment variable as the root. For example, if the follwing variables are specified: 146 | - `ESP_IDF_GLOB_HOMEDIR_BASE=/home/someuser` 147 | - `ESP_IDF_GLOB_HOMEDIR_FOO=foo*` 148 | - `ESP_IDF_GLOB_HOMEDIR_BAR=bar*` 149 | ... then all files and directories matching 'foo*' or 'bar*' from the home directory of the user will be copied in theESP-IDF C project. 150 | 151 | Note also that `_HOMEDIR` in the above example is optional, and is just a mechanism allowing the user to specify more than base directory and its glob patterns. 152 | 153 | 154 | - `ESP_IDF_PIO_CONF_XXX` (*pio* builder only): 155 | 156 | A PlatformIO setting (or multiple settings separated by a newline) that will be passed as-is to the `platformio.ini` file of the C project that compiles the ESP-IDF. 157 | - Check [the PlatformIO documentation](https://docs.platformio.org/en/latest/projectconf/index.html) for more information as to what settings you can pass via this variable. 158 | - Note also that this is not one variable - but rather - a family of variables all starting with `ESP_IDF_PIO_CONF_`. I.e., passing `ESP_IDF_PIO_CONF_1` as well as `ESP_IDF_PIO_CONF_FOO` is valid and all such variables will be honored 159 | 160 | - `ESP_IDF_CMAKE_GENERATOR` (*native* builder only): 161 | 162 | The CMake generator to be used when building the ESP-IDF SDK. If not specified or set to `default`, Ninja will be used on all platforms except Linux/aarch64, where 163 | (for now) the Unix Makefiles generator will be used, as there are no Ninja builds for that platform provided by Espressif yet. 164 | Possible values for this environment variable are [the names of all command-line generators that CMake supports](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html#cmake-generators) with **spaces and hyphens removed**. 165 | 166 | - `MCU`: 167 | 168 | The MCU name (i.e. `esp32`, `esp32s2`, `esp32s3` `esp32c3` and `esp32h2`). 169 | 170 | - If not set this will be automatically detected from the cargo target. 171 | 172 | - Note that [older ESP-IDF versions might not support all MCUs from above](https://github.com/espressif/esp-idf#esp-idf-release-and-soc-compatibility). 173 | 174 | ## More info 175 | 176 | If you are interested how it all works under the hood, check the [build.rs](build/build.rs) 177 | build script of this crate. 178 | --------------------------------------------------------------------------------