├── .gitignore ├── examples ├── .env.example ├── rust-toolchain.toml ├── .gitignore ├── build.rs ├── partitions.csv ├── esp-ota-test.py ├── .cargo │ └── config.toml ├── Cargo.toml ├── src │ └── main.rs └── Cargo.lock ├── partition-reader ├── part.bin ├── Cargo.toml ├── Cargo.lock └── src │ └── main.rs ├── simple-ota-server ├── firmware.bin ├── Cargo.toml ├── Cargo.lock └── src │ └── main.rs ├── partitions.csv.template ├── src ├── mmu_ll │ ├── not_selected.rs │ ├── esp32c3.rs │ ├── esp32s3.rs │ ├── mod.rs │ ├── esp32c2.rs │ ├── esp32c6.rs │ ├── esp32h2.rs │ ├── esp32s2.rs │ └── esp32.rs ├── logging.rs ├── helpers.rs ├── structs.rs ├── mmu_hal.rs ├── crc32.rs └── lib.rs ├── Cargo.toml ├── LICENSE ├── README.md └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /examples/.env.example: -------------------------------------------------------------------------------- 1 | SSID= 2 | PSK= 3 | OTA_IP= 4 | -------------------------------------------------------------------------------- /examples/rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "esp" 3 | -------------------------------------------------------------------------------- /partition-reader/part.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/filipton/esp-hal-ota/HEAD/partition-reader/part.bin -------------------------------------------------------------------------------- /simple-ota-server/firmware.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/filipton/esp-hal-ota/HEAD/simple-ota-server/firmware.bin -------------------------------------------------------------------------------- /partition-reader/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "partition-reader" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /partition-reader/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "partition-reader" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /simple-ota-server/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "simple-ota-server" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | crc32fast = "1.4.2" 10 | -------------------------------------------------------------------------------- /partitions.csv.template: -------------------------------------------------------------------------------- 1 | # Name, Type, SubType, Offset, Size, Flags 2 | nvs, data, nvs, 0x9000, 0x4000, 3 | otadata, data, ota, 0xd000, 0x2000, 4 | phy_init, data, phy, 0xf000, 0x1000, 5 | ota_0, app, ota_0, 0x10000, 0x100000, 6 | ota_1, app, ota_1, 0x110000, 0x100000, 7 | -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # These are backup files generated by rustfmt 7 | **/*.rs.bk 8 | 9 | # MSVC Windows builds of rustc generate these, which store debugging information 10 | *.pdb 11 | .env 12 | out*.bin 13 | -------------------------------------------------------------------------------- /examples/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("cargo:rerun-if-changed=*.env*"); 3 | if let Ok(mut iter) = dotenvy::dotenv_iter() { 4 | while let Some(Ok((key, value))) = iter.next() { 5 | println!("cargo:rustc-env={key}={value}"); 6 | } 7 | } 8 | 9 | println!("cargo:rustc-link-arg-bins=-Tlinkall.x"); 10 | } 11 | -------------------------------------------------------------------------------- /src/mmu_ll/not_selected.rs: -------------------------------------------------------------------------------- 1 | pub fn mmu_ll_get_page_size(_mmu_id: u32) -> u32 { 2 | 0 3 | } 4 | 5 | pub fn mmu_ll_get_entry_id(_mmu_id: u32, _vaddr: u32) -> u32 { 6 | 0 7 | } 8 | 9 | pub fn mmu_ll_entry_id_to_paddr_base(_mmu_id: u32, _entry_id: u32) -> u32 { 10 | 0 11 | } 12 | 13 | pub fn mmu_ll_check_entry_valid(_mmu_id: u32, _entry_id: u32) -> bool { 14 | false 15 | } 16 | -------------------------------------------------------------------------------- /examples/partitions.csv: -------------------------------------------------------------------------------- 1 | # Name, Type, SubType, Offset, Size, Flags 2 | nvs, data, nvs, 0x9000, 0x4000, 3 | otadata, data, ota, 0xd000, 0x2000, 4 | phy_init, data, phy, 0xf000, 0x1000, 5 | factory, app, factory, 0x10000, 0x100000, 6 | ota_0, app, ota_0, 0x110000, 0x100000, 7 | ota_1, app, ota_1, 0x210000, 0x100000, 8 | #ota_2, app, ota_2, 0x310000, 0x10000, 9 | -------------------------------------------------------------------------------- /examples/esp-ota-test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | 4 | idf_path = os.environ["IDF_PATH"] # get value of IDF_PATH from environment 5 | otatool_dir = os.path.join(idf_path, "components", "app_update") # otatool.py lives in $IDF_PATH/components/app_update 6 | 7 | sys.path.append(otatool_dir) # this enables Python to find otatool module 8 | from otatool import * # import all names inside otatool module 9 | 10 | target = OtatoolTarget("/dev/ttyACM0") 11 | target.switch_ota_partition(0) 12 | #print(target._get_otadata_info()) 13 | 14 | #target.erase_otadata() 15 | #target.erase_ota_partition(1) 16 | #target.switch_ota_partition(1) 17 | -------------------------------------------------------------------------------- /simple-ota-server/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "cfg-if" 7 | version = "1.0.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 10 | 11 | [[package]] 12 | name = "crc32fast" 13 | version = "1.4.2" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" 16 | dependencies = [ 17 | "cfg-if", 18 | ] 19 | 20 | [[package]] 21 | name = "simple-ota-server" 22 | version = "0.1.0" 23 | dependencies = [ 24 | "crc32fast", 25 | ] 26 | -------------------------------------------------------------------------------- /src/mmu_ll/esp32c3.rs: -------------------------------------------------------------------------------- 1 | const SOC_MMU_VADDR_MASK: u32 = 0x7FFFFF; 2 | const DR_REG_MMU_TABLE: u32 = 0x600c5000; 3 | const SOC_MMU_VALID_VAL_MASK: u32 = 0xff; 4 | const SOC_MMU_INVALID: u32 = 1 << 8; 5 | 6 | pub fn mmu_ll_get_page_size(_mmu_id: u32) -> u32 { 7 | crate::mmu_hal::MMU_PAGE_64KB 8 | } 9 | 10 | pub fn mmu_ll_get_entry_id(_mmu_id: u32, vaddr: u32) -> u32 { 11 | (vaddr & SOC_MMU_VADDR_MASK) >> 16 12 | } 13 | 14 | pub fn mmu_ll_entry_id_to_paddr_base(_mmu_id: u32, entry_id: u32) -> u32 { 15 | let ptr = (DR_REG_MMU_TABLE + entry_id * 4) as *const u32; 16 | unsafe { ((*ptr) & SOC_MMU_VALID_VAL_MASK) << 16 } 17 | } 18 | 19 | pub fn mmu_ll_check_entry_valid(_mmu_id: u32, entry_id: u32) -> bool { 20 | let ptr = (DR_REG_MMU_TABLE + entry_id * 4) as *const u32; 21 | unsafe { ((*ptr) & SOC_MMU_INVALID) == 0 } 22 | } 23 | -------------------------------------------------------------------------------- /src/mmu_ll/esp32s3.rs: -------------------------------------------------------------------------------- 1 | const SOC_MMU_VADDR_MASK: u32 = 0x1FFFFFF; 2 | const DR_REG_MMU_TABLE: u32 = 0x600C5000; 3 | const SOC_MMU_VALID_VAL_MASK: u32 = 0x3fff; 4 | const SOC_MMU_INVALID: u32 = 1 << 14; 5 | 6 | pub fn mmu_ll_get_page_size(_mmu_id: u32) -> u32 { 7 | crate::mmu_hal::MMU_PAGE_64KB 8 | } 9 | 10 | pub fn mmu_ll_get_entry_id(_mmu_id: u32, vaddr: u32) -> u32 { 11 | (vaddr & SOC_MMU_VADDR_MASK) >> 16 12 | } 13 | 14 | pub fn mmu_ll_entry_id_to_paddr_base(_mmu_id: u32, entry_id: u32) -> u32 { 15 | let ptr = (DR_REG_MMU_TABLE + entry_id * 4) as *const u32; 16 | unsafe { ((*ptr) & SOC_MMU_VALID_VAL_MASK) << 16 } 17 | } 18 | 19 | pub fn mmu_ll_check_entry_valid(_mmu_id: u32, entry_id: u32) -> bool { 20 | let ptr = (DR_REG_MMU_TABLE + entry_id * 4) as *const u32; 21 | unsafe { ((*ptr) & SOC_MMU_INVALID) == 0 } 22 | } 23 | -------------------------------------------------------------------------------- /src/logging.rs: -------------------------------------------------------------------------------- 1 | macro_rules! debug { 2 | ($($arg:tt)*) => { 3 | #[cfg(feature = "defmt")] 4 | defmt::debug!($($arg)*); 5 | #[cfg(feature = "log")] 6 | log::debug!($($arg)*); 7 | }; 8 | } 9 | 10 | macro_rules! info { 11 | ($($arg:tt)*) => { 12 | #[cfg(feature = "defmt")] 13 | defmt::info!($($arg)*); 14 | #[cfg(feature = "log")] 15 | log::info!($($arg)*); 16 | }; 17 | } 18 | 19 | macro_rules! warn { 20 | ($($arg:tt)*) => { 21 | #[cfg(feature = "defmt")] 22 | defmt::warn!($($arg)*); 23 | #[cfg(feature = "log")] 24 | log::warn!($($arg)*); 25 | }; 26 | } 27 | 28 | macro_rules! error { 29 | ($($arg:tt)*) => { 30 | #[cfg(feature = "defmt")] 31 | defmt::error!($($arg)*); 32 | #[cfg(feature = "log")] 33 | log::error!($($arg)*); 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /examples/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [alias] 2 | esp32c3 = "run --no-default-features --features=esp32c3 --target=riscv32imc-unknown-none-elf" 3 | esp32s3 = "run --no-default-features --features=esp32s3 --target=xtensa-esp32s3-none-elf" 4 | esp32 = "run --no-default-features --features=esp32 --target=xtensa-esp32-none-elf" 5 | 6 | [target.'cfg(target_arch = "riscv32")'] 7 | runner = "espflash flash --monitor --partition-table ./partitions.csv --erase-parts otadata" 8 | rustflags = [ 9 | "-C", "force-frame-pointers", 10 | ] 11 | 12 | [target.'cfg(target_arch = "xtensa")'] 13 | runner = "espflash flash --monitor --partition-table ./partitions.csv --erase-parts otadata" 14 | rustflags = [ 15 | "-C", "link-arg=-nostartfiles", 16 | ] 17 | 18 | [build] 19 | target = "xtensa-esp32s3-none-elf" #default esp32s3 20 | 21 | [env] 22 | ESP_LOG="INFO" 23 | 24 | [unstable] 25 | build-std = ["core", "alloc"] 26 | -------------------------------------------------------------------------------- /partition-reader/src/main.rs: -------------------------------------------------------------------------------- 1 | const PARTITION_BYTES: &[u8] = include_bytes!("../part.bin"); 2 | 3 | fn main() { 4 | let chunks = PARTITION_BYTES.chunks(32); 5 | for chunk in chunks { 6 | if chunk == &[0xFF; 32] { 7 | break; 8 | } 9 | 10 | let magic = &chunk[0..2]; 11 | if magic != &[0xAA, 0x50] { 12 | continue; 13 | } 14 | 15 | let p_type = &chunk[2]; 16 | let p_subtype = &chunk[3]; 17 | let p_offset = u32::from_le_bytes(chunk[4..8].try_into().unwrap()); 18 | let p_size = u32::from_le_bytes(chunk[8..12].try_into().unwrap()); 19 | let p_name = core::str::from_utf8(&chunk[12..28]).unwrap(); 20 | let p_flags = u32::from_le_bytes(chunk[28..32].try_into().unwrap()); 21 | 22 | println!("{magic:?} {p_type} {p_subtype} {p_offset} {p_size} {p_name} {p_flags}"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /simple-ota-server/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | io::{Read, Write}, 3 | net::TcpListener, 4 | }; 5 | 6 | fn main() { 7 | let binary = std::fs::read("./firmware.bin").unwrap(); 8 | let binary_crc = crc32fast::hash(&binary); 9 | 10 | println!("BINARY_SIZE: {}", binary.len()); 11 | println!("BINARY CRC32: {}", binary_crc); 12 | 13 | let listener = TcpListener::bind("0.0.0.0:6969").unwrap(); 14 | for stream in listener.incoming() { 15 | println!("Connection"); 16 | let mut stream = stream.unwrap(); 17 | 18 | _ = stream.write_all(&(binary.len() as u32).to_le_bytes()); 19 | _ = stream.write_all(&binary_crc.to_le_bytes()); 20 | 21 | let chunks = binary.chunks(4096 * 2); 22 | let mut buf = [0; 1]; 23 | for chunk in chunks { 24 | println!("Writing: {}", chunk.len()); 25 | 26 | _ = stream.write_all(chunk); 27 | _ = stream.read_exact(&mut buf); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "esp-hal-ota" 3 | version = "0.4.5" 4 | edition = "2024" 5 | license = "MIT" 6 | description = "OTA library for esp-hal" 7 | repository = "https://github.com/filipton/esp-hal-ota" 8 | 9 | [lib] 10 | 11 | [dependencies] 12 | embedded-storage = "0.3.1" 13 | log = { version = "0.4.28", optional = true } 14 | defmt = { version = "1.0.1", optional = true } 15 | 16 | esp32 = { version = "0.39.0", optional = true } 17 | 18 | esp32s2 = { version = "0.30.0", optional = true } 19 | esp32s3 = { version = "0.34.0", optional = true } 20 | 21 | esp32c2 = { version = "0.28.0", optional = true } 22 | esp32c3 = { version = "0.31.0", optional = true } 23 | esp32c6 = { version = "0.22.0", optional = true } 24 | 25 | esp32h2 = { version = "0.18.0", optional = true } 26 | 27 | [features] 28 | default = [] 29 | log = ["dep:log"] 30 | defmt = ["dep:defmt"] 31 | 32 | esp32 = ["dep:esp32"] 33 | 34 | esp32s2 = ["dep:esp32s2"] 35 | esp32s3 = ["dep:esp32s3"] 36 | 37 | esp32c2 = ["dep:esp32c2"] 38 | esp32c3 = ["dep:esp32c3"] 39 | esp32c6 = ["dep:esp32c6"] 40 | 41 | esp32h2 = ["dep:esp32h2"] 42 | -------------------------------------------------------------------------------- /src/helpers.rs: -------------------------------------------------------------------------------- 1 | #[inline(always)] 2 | /// Helper funcion! 3 | /// Change seq to partition number 4 | pub const fn seq_to_part(seq: u32, partitions_count: usize) -> usize { 5 | ((seq as usize).saturating_sub(1)) % partitions_count 6 | } 7 | 8 | #[inline(always)] 9 | /// Helper funcion! 10 | /// If crc of seq is correct it returns seq, otherwise default value is returned 11 | pub fn seq_or_default(seq: &[u8], crc: u32, default: u32) -> u32 { 12 | let crc_calc = crate::crc32::calc_crc32(seq, 0xFFFFFFFF); 13 | if crc == crc_calc { 14 | return u32::from_le_bytes(seq.try_into().expect("Wrong size?")); 15 | } 16 | 17 | default 18 | } 19 | 20 | #[inline(always)] 21 | /// Helper function! 22 | /// Check if crc is correct for given seq 23 | pub fn is_crc_seq_correct(seq: u32, crc: u32) -> bool { 24 | let bytes = unsafe { 25 | let mut buf = [0; 4]; //u32 26 | core::ptr::copy_nonoverlapping(&seq as *const u32 as *const u8, buf.as_mut_ptr(), 4); 27 | 28 | buf 29 | }; 30 | 31 | let crc_calc = crate::crc32::calc_crc32(&bytes, 0xFFFFFFFF); 32 | crc == crc_calc 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [year] [fullname] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/mmu_ll/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(any(feature = "esp32", feature = "esp32s2"))] 2 | macro_rules! soc_address_in_bus { 3 | ($bus_name:ident, $vaddr:ident) => {{ 4 | (concat_idents!($bus_name, _ADDRESS_LOW)..concat_idents!($bus_name, _ADDRESS_HIGH)) 5 | .contains(&$vaddr) 6 | }}; 7 | } 8 | 9 | #[cfg(feature = "esp32")] 10 | mod esp32; 11 | #[cfg(feature = "esp32")] 12 | pub use esp32::*; 13 | 14 | #[cfg(feature = "esp32s2")] 15 | mod esp32s2; 16 | #[cfg(feature = "esp32s2")] 17 | pub use esp32s2::*; 18 | 19 | #[cfg(feature = "esp32s3")] 20 | mod esp32s3; 21 | #[cfg(feature = "esp32s3")] 22 | pub use esp32s3::*; 23 | 24 | #[cfg(feature = "esp32c2")] 25 | mod esp32c2; 26 | #[cfg(feature = "esp32c2")] 27 | pub use esp32c2::*; 28 | 29 | #[cfg(feature = "esp32c3")] 30 | mod esp32c3; 31 | #[cfg(feature = "esp32c3")] 32 | pub use esp32c3::*; 33 | 34 | #[cfg(feature = "esp32c6")] 35 | mod esp32c6; 36 | #[cfg(feature = "esp32c6")] 37 | pub use esp32c6::*; 38 | 39 | #[cfg(feature = "esp32h2")] 40 | mod esp32h2; 41 | #[cfg(feature = "esp32h2")] 42 | pub use esp32h2::*; 43 | 44 | #[cfg(not(any( 45 | feature = "esp32", 46 | feature = "esp32s2", 47 | feature = "esp32s3", 48 | feature = "esp32c2", 49 | feature = "esp32c3", 50 | feature = "esp32c6", 51 | feature = "esp32h2" 52 | )))] 53 | mod not_selected; 54 | 55 | #[cfg(not(any( 56 | feature = "esp32", 57 | feature = "esp32s2", 58 | feature = "esp32s3", 59 | feature = "esp32c2", 60 | feature = "esp32c3", 61 | feature = "esp32c6", 62 | feature = "esp32h2" 63 | )))] 64 | pub use not_selected::*; 65 | -------------------------------------------------------------------------------- /src/structs.rs: -------------------------------------------------------------------------------- 1 | pub(crate) type Result = core::result::Result; 2 | 3 | #[derive(Debug, PartialEq)] 4 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 5 | pub enum OtaError { 6 | NotEnoughPartitions, 7 | OtaNotStarted, 8 | FlashRWError, 9 | WrongCRC, 10 | WrongOTAPArtitionOrder, 11 | OtaVerifyError, 12 | CannotFindCurrentBootPartition, 13 | } 14 | 15 | #[derive(Clone)] 16 | pub struct FlashProgress { 17 | pub last_crc: u32, 18 | pub flash_offset: u32, 19 | pub flash_size: u32, 20 | pub remaining: u32, 21 | 22 | pub target_partition: usize, 23 | pub target_crc: u32, 24 | } 25 | 26 | #[derive(Debug)] 27 | pub struct PartitionInfo { 28 | pub ota_partitions: [(u32, u32); 16], 29 | pub ota_partitions_count: usize, 30 | 31 | pub otadata_offset: u32, 32 | pub otadata_size: u32, 33 | } 34 | 35 | #[repr(u32)] 36 | #[derive(Debug, PartialEq)] 37 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 38 | pub enum OtaImgState { 39 | EspOtaImgNew = 0x0, 40 | EspOtaImgPendingVerify = 0x1, 41 | EspOtaImgValid = 0x2, 42 | EspOtaImgInvalid = 0x3, 43 | EspOtaImgAborted = 0x4, 44 | EspOtaImgUndefined = 0xFFFFFFFF, 45 | } 46 | 47 | #[repr(C)] 48 | #[derive(Debug)] 49 | pub struct EspOtaSelectEntry { 50 | pub seq: u32, 51 | pub seq_label: [u8; 20], 52 | pub ota_state: OtaImgState, 53 | pub crc: u32, 54 | } 55 | 56 | impl EspOtaSelectEntry { 57 | /// Check if crc(of seq) is correct, if not - its setting seq to 0 58 | pub fn check_crc(&mut self) { 59 | if !crate::helpers::is_crc_seq_correct(self.seq, self.crc) { 60 | self.seq = 0; // set seq to 0 if crc not correct! 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/mmu_ll/esp32c2.rs: -------------------------------------------------------------------------------- 1 | use crate::mmu_hal::{MMU_PAGE_16KB, MMU_PAGE_32KB, MMU_PAGE_64KB}; 2 | 3 | const DR_REG_MMU_TABLE: u32 = 0x600c5000; 4 | const SOC_MMU_VALID_VAL_MASK: u32 = 0x3f; 5 | const SOC_MMU_INVALID: u32 = 1 << 6; 6 | 7 | fn soc_mmu_vaddr_mask(mmu_id: u32) -> u32 { 8 | mmu_ll_get_page_size(mmu_id) * 64 - 1 9 | } 10 | 11 | pub fn mmu_ll_get_page_size(_mmu_id: u32) -> u32 { 12 | let extmem = unsafe { &*esp32c2::EXTMEM::ptr() }; 13 | let cache_mmu_page_size = extmem.cache_conf_misc().read().cache_mmu_page_size().bits(); 14 | match cache_mmu_page_size { 15 | 0 => MMU_PAGE_16KB, 16 | 1 => MMU_PAGE_32KB, 17 | _ => MMU_PAGE_64KB, 18 | } 19 | } 20 | 21 | pub fn mmu_ll_get_entry_id(mmu_id: u32, vaddr: u32) -> u32 { 22 | let shift_code = match mmu_ll_get_page_size(mmu_id) { 23 | MMU_PAGE_64KB => 16, 24 | MMU_PAGE_32KB => 15, 25 | MMU_PAGE_16KB => 14, 26 | _ => { 27 | error!("mmu_ll_get_entry_id failed!"); 28 | 29 | 0 30 | } 31 | }; 32 | 33 | (vaddr & soc_mmu_vaddr_mask(mmu_id)) >> shift_code 34 | } 35 | 36 | pub fn mmu_ll_entry_id_to_paddr_base(mmu_id: u32, entry_id: u32) -> u32 { 37 | let shift_code = match mmu_ll_get_page_size(mmu_id) { 38 | MMU_PAGE_64KB => 16, 39 | MMU_PAGE_32KB => 15, 40 | MMU_PAGE_16KB => 14, 41 | _ => { 42 | error!("mmu_ll_entry_id_to_paddr_base failed!"); 43 | 44 | 0 45 | } 46 | }; 47 | 48 | let ptr = (DR_REG_MMU_TABLE + entry_id * 4) as *const u32; 49 | unsafe { ((*ptr) & SOC_MMU_VALID_VAL_MASK) << shift_code } 50 | } 51 | 52 | pub fn mmu_ll_check_entry_valid(_mmu_id: u32, entry_id: u32) -> bool { 53 | let ptr = (DR_REG_MMU_TABLE + entry_id * 4) as *const u32; 54 | unsafe { ((*ptr) & SOC_MMU_INVALID) == 0 } 55 | } 56 | -------------------------------------------------------------------------------- /src/mmu_hal.rs: -------------------------------------------------------------------------------- 1 | pub const MMU_PAGE_8KB: u32 = 0x2000; 2 | pub const MMU_PAGE_16KB: u32 = 0x4000; 3 | pub const MMU_PAGE_32KB: u32 = 0x8000; 4 | pub const MMU_PAGE_64KB: u32 = 0x10000; 5 | 6 | fn mmu_hal_pages_to_bytes(mmu_id: u32, page_num: u32) -> u32 { 7 | let mmu_page_size = crate::mmu_ll::mmu_ll_get_page_size(mmu_id); 8 | let shift_code = match mmu_page_size { 9 | MMU_PAGE_64KB => 16, 10 | MMU_PAGE_32KB => 15, 11 | MMU_PAGE_16KB => 14, 12 | _ => panic!("WRONG MMU_PAGE_SIZE! 0x{:X?}", mmu_page_size), 13 | }; 14 | 15 | page_num << shift_code 16 | } 17 | 18 | pub fn esp_get_current_running_partition(partitions: &[(u32, u32)]) -> Option { 19 | // NOTE: 20 | // mmu_id is always 0 because s_vaddr_to_paddr is using 0 for all targets 21 | // except esp32p4 (per SOC_MMU_PER_EXT_MEM_TARGET define) 22 | // 23 | // https://github.com/espressif/esp-idf/blob/b5ac4fbdf9e9fb320bb0a98ee4fbaa18f8566f37/components/esp_mm/esp_mmu_map.c#L754 24 | let mmu_id = 0; 25 | 26 | let ptr = esp_get_current_running_partition as *const () as *const u32; 27 | let entry_id = crate::mmu_ll::mmu_ll_get_entry_id(mmu_id, ptr as u32); 28 | 29 | if !crate::mmu_ll::mmu_ll_check_entry_valid(mmu_id, entry_id) { 30 | error!("mmu_ll_check_entry_valid failed!"); 31 | 32 | return None; 33 | } 34 | 35 | // page_num is always 1 36 | // https://github.com/espressif/esp-idf/blob/master/components/hal/mmu_hal.c#L129 37 | let page_size_in_bytes = mmu_hal_pages_to_bytes(mmu_id, 1); 38 | let offset = (ptr as u32) % page_size_in_bytes; 39 | 40 | let paddr_base = crate::mmu_ll::mmu_ll_entry_id_to_paddr_base(mmu_id, entry_id); 41 | let paddr = paddr_base | offset; 42 | 43 | for (i, part) in partitions.iter().enumerate() { 44 | if paddr >= part.0 && paddr < part.0 + part.1 { 45 | return Some(i); 46 | } 47 | } 48 | 49 | None 50 | } 51 | -------------------------------------------------------------------------------- /examples/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "esp-hal-ota-example" 3 | version = "0.1.0" 4 | authors = ["filipton "] 5 | edition = "2024" 6 | license = "MIT OR Apache-2.0" 7 | 8 | [dependencies] 9 | esp-backtrace = { version = "0.18.0", features = [ "panic-handler", "println" ] } 10 | esp-hal = { version = "1.0.0-rc.1", features = ["unstable"] } 11 | esp-println = { version = "0.16.0", features = ["log-04"] } 12 | log = { version = "0.4.28" } 13 | esp-radio = { version = "0.16.0", features = [ "unstable", "wifi", "ble" ] } 14 | esp-rtos = { version = "0.1.0", features = ["esp-radio", "embassy"] } 15 | embassy-executor = { version = "0.9.1", package = "embassy-executor", features = ["arch-riscv32"] } 16 | embassy-net = { version = "0.7.1", features = ["tcp", "udp", "dhcpv4", "medium-ethernet"] } 17 | embassy-time = { version = "0.5.0" } 18 | esp-storage = { version = "0.8.0", features = [] } 19 | esp-hal-ota = { path = "../", features = ["log"] } 20 | static_cell = { version = "2.1.1", features = ["nightly"] } 21 | esp-alloc = "0.9.0" 22 | esp-bootloader-esp-idf = { version = "0.3.0", features = ["log-04"] } 23 | 24 | [build-dependencies] 25 | dotenvy = "0.15.7" 26 | 27 | [profile.dev] 28 | # Rust debug is too slow. 29 | # For debug builds always builds with some optimization 30 | opt-level = "s" 31 | 32 | [profile.release] 33 | codegen-units = 1 # LLVM can perform better optimizations using a single thread 34 | debug = 2 35 | debug-assertions = false 36 | incremental = false 37 | lto = 'fat' 38 | opt-level = 2 39 | overflow-checks = false 40 | 41 | [features] 42 | default = ["esp32s3"] 43 | esp32s3 = ["esp-backtrace/esp32s3", "esp-hal/esp32s3", "esp-println/esp32s3", "esp-radio/esp32s3", "esp-rtos/esp32s3", "esp-storage/esp32s3", "esp-hal-ota/esp32s3", "esp-bootloader-esp-idf/esp32s3"] 44 | esp32c3 = ["esp-backtrace/esp32c3", "esp-hal/esp32c3", "esp-println/esp32c3", "esp-radio/esp32c3", "esp-rtos/esp32c3", "esp-storage/esp32c3", "esp-hal-ota/esp32c3", "esp-bootloader-esp-idf/esp32c3"] 45 | esp32 = ["esp-backtrace/esp32", "esp-hal/esp32", "esp-println/esp32", "esp-radio/esp32", "esp-rtos/esp32", "esp-storage/esp32", "esp-hal-ota/esp32", "esp-bootloader-esp-idf/esp32"] 46 | -------------------------------------------------------------------------------- /src/mmu_ll/esp32c6.rs: -------------------------------------------------------------------------------- 1 | use crate::mmu_hal::{MMU_PAGE_8KB, MMU_PAGE_16KB, MMU_PAGE_32KB, MMU_PAGE_64KB}; 2 | 3 | const SOC_MMU_ENTRY_NUM: u32 = 256; 4 | const SOC_MMU_VALID_VAL_MASK: u32 = 0x1ff; 5 | const SOC_MMU_VALID: u32 = 1 << 9; 6 | 7 | fn soc_mmu_vaddr_mask(mmu_id: u32) -> u32 { 8 | mmu_ll_get_page_size(mmu_id) * SOC_MMU_ENTRY_NUM - 1 9 | } 10 | 11 | pub fn mmu_ll_get_page_size(_mmu_id: u32) -> u32 { 12 | let spi_mem = unsafe { &*esp32c6::SPI0::ptr() }; 13 | let page_size_code = spi_mem.mmu_power_ctrl().read().spi_mmu_page_size().bits(); 14 | 15 | match page_size_code { 16 | 0 => MMU_PAGE_64KB, 17 | 1 => MMU_PAGE_32KB, 18 | 2 => MMU_PAGE_16KB, 19 | _ => MMU_PAGE_8KB, 20 | } 21 | } 22 | 23 | pub fn mmu_ll_get_entry_id(mmu_id: u32, vaddr: u32) -> u32 { 24 | let shift_code = match mmu_ll_get_page_size(mmu_id) { 25 | MMU_PAGE_64KB => 16, 26 | MMU_PAGE_32KB => 15, 27 | MMU_PAGE_16KB => 14, 28 | MMU_PAGE_8KB => 13, 29 | _ => { 30 | error!("mmu_ll_get_entry_id failed!"); 31 | 32 | 0 33 | } 34 | }; 35 | 36 | (vaddr & soc_mmu_vaddr_mask(mmu_id)) >> shift_code 37 | } 38 | 39 | pub fn mmu_ll_entry_id_to_paddr_base(mmu_id: u32, entry_id: u32) -> u32 { 40 | let shift_code = match mmu_ll_get_page_size(mmu_id) { 41 | MMU_PAGE_64KB => 16, 42 | MMU_PAGE_32KB => 15, 43 | MMU_PAGE_16KB => 14, 44 | MMU_PAGE_8KB => 13, 45 | _ => { 46 | error!("mmu_ll_entry_id_to_paddr_base failed!"); 47 | 48 | 0 49 | } 50 | }; 51 | 52 | let spi_mem = unsafe { &*esp32c6::SPI0::ptr() }; 53 | spi_mem 54 | .mmu_item_index() 55 | .write(|w| unsafe { w.spi_mmu_item_index().bits(entry_id) }); 56 | 57 | let mmu_item_content = spi_mem 58 | .mmu_item_content() 59 | .read() 60 | .spi_mmu_item_content() 61 | .bits(); 62 | 63 | (mmu_item_content & SOC_MMU_VALID_VAL_MASK) << shift_code 64 | } 65 | 66 | pub fn mmu_ll_check_entry_valid(_mmu_id: u32, entry_id: u32) -> bool { 67 | let spi_mem = unsafe { &*esp32c6::SPI0::ptr() }; 68 | spi_mem 69 | .mmu_item_index() 70 | .write(|w| unsafe { w.spi_mmu_item_index().bits(entry_id) }); 71 | 72 | let mmu_item_content = spi_mem 73 | .mmu_item_content() 74 | .read() 75 | .spi_mmu_item_content() 76 | .bits(); 77 | 78 | (mmu_item_content & SOC_MMU_VALID) != 0 79 | } 80 | -------------------------------------------------------------------------------- /src/mmu_ll/esp32h2.rs: -------------------------------------------------------------------------------- 1 | use crate::mmu_hal::{MMU_PAGE_8KB, MMU_PAGE_16KB, MMU_PAGE_32KB, MMU_PAGE_64KB}; 2 | 3 | const SOC_MMU_ENTRY_NUM: u32 = 256; 4 | const SOC_MMU_VALID_VAL_MASK: u32 = 0x1ff; 5 | const SOC_MMU_VALID: u32 = 1 << 9; 6 | 7 | fn soc_mmu_vaddr_mask(mmu_id: u32) -> u32 { 8 | mmu_ll_get_page_size(mmu_id) * SOC_MMU_ENTRY_NUM - 1 9 | } 10 | 11 | pub fn mmu_ll_get_page_size(_mmu_id: u32) -> u32 { 12 | let spi_mem = unsafe { &*esp32h2::SPI0::ptr() }; 13 | let page_size_code = spi_mem.mmu_power_ctrl().read().spi_mmu_page_size().bits(); 14 | 15 | match page_size_code { 16 | 0 => MMU_PAGE_64KB, 17 | 1 => MMU_PAGE_32KB, 18 | 2 => MMU_PAGE_16KB, 19 | _ => MMU_PAGE_8KB, 20 | } 21 | } 22 | 23 | pub fn mmu_ll_get_entry_id(mmu_id: u32, vaddr: u32) -> u32 { 24 | let shift_code = match mmu_ll_get_page_size(mmu_id) { 25 | MMU_PAGE_64KB => 16, 26 | MMU_PAGE_32KB => 15, 27 | MMU_PAGE_16KB => 14, 28 | MMU_PAGE_8KB => 13, 29 | _ => { 30 | error!("mmu_ll_get_entry_id failed!"); 31 | 32 | 0 33 | } 34 | }; 35 | 36 | (vaddr & soc_mmu_vaddr_mask(mmu_id)) >> shift_code 37 | } 38 | 39 | pub fn mmu_ll_entry_id_to_paddr_base(mmu_id: u32, entry_id: u32) -> u32 { 40 | let shift_code = match mmu_ll_get_page_size(mmu_id) { 41 | MMU_PAGE_64KB => 16, 42 | MMU_PAGE_32KB => 15, 43 | MMU_PAGE_16KB => 14, 44 | MMU_PAGE_8KB => 13, 45 | _ => { 46 | error!("mmu_ll_entry_id_to_paddr_base failed!"); 47 | 48 | 0 49 | } 50 | }; 51 | 52 | let spi_mem = unsafe { &*esp32h2::SPI0::ptr() }; 53 | spi_mem 54 | .mmu_item_index() 55 | .write(|w| unsafe { w.spi_mmu_item_index().bits(entry_id) }); 56 | 57 | let mmu_item_content = spi_mem 58 | .mmu_item_content() 59 | .read() 60 | .spi_mmu_item_content() 61 | .bits(); 62 | 63 | (mmu_item_content & SOC_MMU_VALID_VAL_MASK) << shift_code 64 | } 65 | 66 | pub fn mmu_ll_check_entry_valid(_mmu_id: u32, entry_id: u32) -> bool { 67 | let spi_mem = unsafe { &*esp32h2::SPI0::ptr() }; 68 | spi_mem 69 | .mmu_item_index() 70 | .write(|w| unsafe { w.spi_mmu_item_index().bits(entry_id) }); 71 | 72 | let mmu_item_content = spi_mem 73 | .mmu_item_content() 74 | .read() 75 | .spi_mmu_item_content() 76 | .bits(); 77 | 78 | (mmu_item_content & SOC_MMU_VALID) != 0 79 | } 80 | -------------------------------------------------------------------------------- /src/mmu_ll/esp32s2.rs: -------------------------------------------------------------------------------- 1 | const SOC_MMU_VADDR_MASK: u32 = 0x3FFFFF; 2 | const DR_REG_MMU_TABLE: u32 = 0x61801000; 3 | const SOC_MMU_VALID_VAL_MASK: u32 = 0x3fff; 4 | const SOC_MMU_INVALID: u32 = 1 << 14; 5 | const SOC_IRAM0_CACHE_ADDRESS_LOW: u32 = 0x40080000; 6 | const SOC_IRAM0_CACHE_ADDRESS_HIGH: u32 = 0x40400000; 7 | const SOC_IRAM1_ADDRESS_LOW: u32 = 0x40400000; 8 | const SOC_IRAM1_ADDRESS_HIGH: u32 = 0x40800000; 9 | const SOC_DROM0_ADDRESS_LOW: u32 = 0x3f000000; 10 | const SOC_DROM0_ADDRESS_HIGH: u32 = 0x3f400000; 11 | const SOC_DRAM0_CACHE_ADDRESS_LOW: u32 = 0x3fc00000; 12 | const SOC_DRAM0_CACHE_ADDRESS_HIGH: u32 = 0x3ff80000; 13 | const SOC_DRAM1_ADDRESS_LOW: u32 = 0x3f800000; 14 | const SOC_DRAM1_ADDRESS_HIGH: u32 = 0x3fc00000; 15 | const SOC_DPORT_CACHE_ADDRESS_LOW: u32 = 0x3f500000; 16 | const SOC_DPORT_CACHE_ADDRESS_HIGH: u32 = 0x3f800000; 17 | const PRO_CACHE_IBUS0_MMU_START: u32 = 0; 18 | const PRO_CACHE_IBUS1_MMU_START: u32 = 0x100; 19 | const PRO_CACHE_IBUS2_MMU_START: u32 = 0x200; 20 | const PRO_CACHE_DBUS0_MMU_START: u32 = 0x300; 21 | const PRO_CACHE_DBUS1_MMU_START: u32 = 0x400; 22 | const PRO_CACHE_DBUS2_MMU_START: u32 = 0x500; 23 | 24 | pub fn mmu_ll_get_page_size(_mmu_id: u32) -> u32 { 25 | crate::mmu_hal::MMU_PAGE_64KB 26 | } 27 | 28 | pub fn mmu_ll_get_entry_id(_mmu_id: u32, vaddr: u32) -> u32 { 29 | let offset = if soc_address_in_bus!(SOC_DROM0, vaddr) { 30 | PRO_CACHE_IBUS2_MMU_START / 4 31 | } else if soc_address_in_bus!(SOC_IRAM0_CACHE, vaddr) { 32 | PRO_CACHE_IBUS0_MMU_START / 4 33 | } else if soc_address_in_bus!(SOC_IRAM1, vaddr) { 34 | PRO_CACHE_IBUS1_MMU_START / 4 35 | } else if soc_address_in_bus!(SOC_DPORT_CACHE, vaddr) { 36 | PRO_CACHE_DBUS2_MMU_START / 4 37 | } else if soc_address_in_bus!(SOC_DRAM1, vaddr) { 38 | PRO_CACHE_DBUS1_MMU_START / 4 39 | } else if soc_address_in_bus!(SOC_DRAM0_CACHE, vaddr) { 40 | PRO_CACHE_DBUS0_MMU_START / 4 41 | } else { 42 | error!("mmu_ll_get_entry_id failed!"); 43 | 44 | 0 45 | }; 46 | 47 | offset + ((vaddr & SOC_MMU_VADDR_MASK) >> 16) 48 | } 49 | 50 | pub fn mmu_ll_entry_id_to_paddr_base(_mmu_id: u32, entry_id: u32) -> u32 { 51 | let ptr = (DR_REG_MMU_TABLE + entry_id * 4) as *const u32; 52 | unsafe { ((*ptr) & SOC_MMU_VALID_VAL_MASK) << 16 } 53 | } 54 | 55 | pub fn mmu_ll_check_entry_valid(_mmu_id: u32, entry_id: u32) -> bool { 56 | let ptr = (DR_REG_MMU_TABLE + entry_id * 4) as *const u32; 57 | unsafe { ((*ptr) & SOC_MMU_INVALID) == 0 } 58 | } 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # esp-hal-ota 2 | OTA for esp-hal (no-std). 3 | 4 | [![crates.io](https://img.shields.io/crates/v/esp-hal-ota.svg)](https://crates.io/crates/esp-hal-ota) 5 | [![MIT license](https://img.shields.io/github/license/mashape/apistatus.svg)]() 6 | 7 | ## Limitations 8 | I cannot test if it works properly on esp32s2,esp32c2,esp32c6 and esp32h2. 9 | But esp32s3, esp32c3 and esp32 are working perfectly fine. 10 | 11 | ## Features 12 | - Obviously OTA updates 13 | - Dynamic partitions reading (so no macros, no reading from partitions.csv) - fully automatic 14 | - Checking currently booted partition (using some pointer magic from ESP-IDF) 15 | - CRC32 verification 16 | 17 | ## Getting started 18 | - Create `partitions.csv` file in project root (copy `partitions.csv.template` file) 19 | - In your project edit `./.cargo/config.toml` file and append `--partition-table ./partitions.csv` to the `runner` attribute 20 | - Optionally append `--erase-parts otadata` to `./cargo/config.toml` to fix some ota issues 21 | 22 | ```toml 23 | [target.xtensa-esp32s3-none-elf] 24 | runner = "espflash flash --monitor --partition-table ./partitions.csv --erase-parts otadata" 25 | ``` 26 | 27 | ## Example 28 | To see real-world example look at `./examples` and `./simple-ota-server` dirs. 29 | 30 | ```rust 31 | let flash_size = 1234; // get it from OTA server 32 | let target_crc = 65436743; // get it from OTA server 33 | 34 | let mut ota = Ota::new(FlashStorage::new()).unwrap(); 35 | ota.ota_begin(flash_size, target_crc); 36 | 37 | let mut buf = [0; 4096]; 38 | loop { 39 | let n = read_next_chunk(&mut buf); 40 | if n == 0 { 41 | break; 42 | } 43 | 44 | let res = ota.ota_write_chunk(&buf[..n]); 45 | if res == Ok(true) { // end of flash 46 | if ota.ota_flush(true, true).is_ok() { // true if you want to verify crc reading flash, and true if you want rollbacks 47 | esp_hal::reset::software_reset(); 48 | } 49 | } 50 | 51 | let progress = (ota.get_ota_progress() * 100) as u8; 52 | log::info!("progress: {}%", progress); 53 | } 54 | ``` 55 | 56 | ### Running example 57 | - You can compile your .bin file using esp-flash 58 | ```bash 59 | espflash save-image --chip esp32c3 ./target/riscv32imc-unknown-none-elf/debug/esp-hal-ota-example ../simple-ota-server/firmware.bin 60 | ``` 61 | 62 | This will generate .bin file from build file for chip. 63 | 64 | ## Todo 65 | - [x] Fully working library 66 | - [x] Simple example 67 | - [x] Better errors 68 | - [x] Other esp32's (like esp32c3, esp32s2, etc..) 69 | - [x] Rollbacks 70 | 71 | ## Resources 72 | - https://github.com/esp-rs/espflash (this led me to esp-idf-part) 73 | - https://github.com/esp-rs/esp-idf-part 74 | - https://github.com/espressif/esp-idf/blob/master/docs/en/api-reference/system/ota.rst (especially Python API) 75 | - https://github.com/python/cpython/blob/main/Modules/binascii.c (internal_crc32) 76 | - https://github.com/espressif/esp-idf/blob/master/components/app_update/esp_ota_ops.c#L552 (esp get current partition (paddr)) 77 | - https://github.com/bjoernQ/esp32c3-ota-experiment (i've only seen this after first experiments, so haven't looked at it yet) 78 | -------------------------------------------------------------------------------- /src/crc32.rs: -------------------------------------------------------------------------------- 1 | const CRC_32_TAB: [u32; 256] = [ 2 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 3 | 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 4 | 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 5 | 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 6 | 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 7 | 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 8 | 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 9 | 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 10 | 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 11 | 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 12 | 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 13 | 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 14 | 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 15 | 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 16 | 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 17 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 18 | 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 19 | 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 20 | 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 21 | 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 22 | 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 23 | 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 24 | 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 25 | 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 26 | 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 27 | 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 28 | 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 29 | 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 30 | 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 31 | 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 32 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 33 | 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, 34 | ]; 35 | 36 | pub fn calc_crc32(buf: &[u8], mut crc: u32) -> u32 { 37 | crc = !crc; 38 | for &elem in buf { 39 | let crc_idx = (crc ^ elem as u32) & 0xFF; 40 | crc = CRC_32_TAB[crc_idx as usize] ^ (crc >> 8); 41 | } 42 | 43 | crc ^ 0xFFFFFFFF 44 | } 45 | -------------------------------------------------------------------------------- /src/mmu_ll/esp32.rs: -------------------------------------------------------------------------------- 1 | const SOC_MMU_VADDR_MASK: u32 = 0x3FFFFF; 2 | const SOC_MMU_INVALID: u32 = 1 << 8; 3 | const MMU_LL_PSRAM_ENTRY_START_ID: u32 = 1152; 4 | const SOC_IRAM0_CACHE_ADDRESS_LOW: u32 = 0x400D0000; 5 | const SOC_IRAM0_CACHE_ADDRESS_HIGH: u32 = 0x40400000; 6 | const SOC_IRAM1_CACHE_ADDRESS_LOW: u32 = 0x40400000; 7 | const SOC_IRAM1_CACHE_ADDRESS_HIGH: u32 = 0x40800000; 8 | const SOC_IROM0_CACHE_ADDRESS_LOW: u32 = 0x40800000; 9 | const SOC_IROM0_CACHE_ADDRESS_HIGH: u32 = 0x40C00000; 10 | const SOC_DRAM1_CACHE_ADDRESS_LOW: u32 = 0x3F800000; 11 | const SOC_DRAM1_CACHE_ADDRESS_HIGH: u32 = 0x3FC00000; 12 | const SOC_DROM0_CACHE_ADDRESS_LOW: u32 = 0x3F400000; 13 | const SOC_DROM0_CACHE_ADDRESS_HIGH: u32 = 0x3F800000; 14 | const DPORT_PRO_FLASH_MMU_TABLE: u32 = 0x3FF10000; 15 | 16 | pub fn mmu_ll_get_page_size(_mmu_id: u32) -> u32 { 17 | crate::mmu_hal::MMU_PAGE_64KB 18 | } 19 | 20 | pub fn mmu_ll_get_entry_id(_mmu_id: u32, vaddr: u32) -> u32 { 21 | let mut offset = 0; 22 | let mut shift_code = 0; 23 | let mut vaddr_mask = 0; 24 | 25 | if soc_address_in_bus!(SOC_DROM0_CACHE, vaddr) { 26 | offset = 0; 27 | shift_code = 16; 28 | vaddr_mask = SOC_MMU_VADDR_MASK; 29 | } else if soc_address_in_bus!(SOC_IRAM0_CACHE, vaddr) { 30 | offset = 64; 31 | shift_code = 16; 32 | vaddr_mask = SOC_MMU_VADDR_MASK; 33 | } else if soc_address_in_bus!(SOC_IRAM1_CACHE, vaddr) { 34 | offset = 128; 35 | shift_code = 16; 36 | vaddr_mask = SOC_MMU_VADDR_MASK; 37 | } else if soc_address_in_bus!(SOC_IROM0_CACHE, vaddr) { 38 | offset = 192; 39 | shift_code = 16; 40 | vaddr_mask = SOC_MMU_VADDR_MASK; 41 | } else if soc_address_in_bus!(SOC_DRAM1_CACHE, vaddr) { 42 | offset = MMU_LL_PSRAM_ENTRY_START_ID; 43 | shift_code = 15; 44 | vaddr_mask = SOC_MMU_VADDR_MASK >> 1; 45 | } else { 46 | error!("mmu_ll_get_entry_id failed!"); 47 | } 48 | 49 | offset + ((vaddr & vaddr_mask) >> shift_code) 50 | } 51 | 52 | pub fn mmu_ll_entry_id_to_paddr_base(_mmu_id: u32, entry_id: u32) -> u32 { 53 | let level = unsafe { dport_interrupt_disable() }; 54 | let mmu_val = unsafe { *(DPORT_PRO_FLASH_MMU_TABLE as *const u32).offset(entry_id as isize) }; 55 | unsafe { dport_interrupt_restore(level) }; 56 | 57 | if entry_id >= MMU_LL_PSRAM_ENTRY_START_ID { 58 | mmu_val << 15 59 | } else { 60 | mmu_val << 16 61 | } 62 | } 63 | 64 | pub fn mmu_ll_check_entry_valid(_mmu_id: u32, entry_id: u32) -> bool { 65 | let level = unsafe { dport_interrupt_disable() }; 66 | let mmu_val = unsafe { *(DPORT_PRO_FLASH_MMU_TABLE as *const u32).offset(entry_id as isize) }; 67 | unsafe { dport_interrupt_restore(level) }; 68 | 69 | (mmu_val & SOC_MMU_INVALID) == 0 70 | } 71 | 72 | // NOTE:Idk if required! 73 | // Only used when using second core etc. 74 | 75 | const SOC_DPORT_WORKAROUND_DIS_INTERRUPT_LVL: u32 = 5; 76 | #[inline(always)] 77 | unsafe fn dport_interrupt_disable() -> u32 { 78 | let level: u32; 79 | 80 | unsafe { 81 | core::arch::asm!( 82 | "rsil {0}, {1}", 83 | out(reg) level, 84 | const SOC_DPORT_WORKAROUND_DIS_INTERRUPT_LVL, 85 | options(nomem, nostack) 86 | ); 87 | } 88 | 89 | level 90 | } 91 | 92 | #[inline(always)] 93 | unsafe fn dport_interrupt_restore(level: u32) { 94 | unsafe { 95 | core::arch::asm!( 96 | "wsr.ps {0}; rsync", 97 | in(reg) level, 98 | options(nomem, nostack) 99 | ); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "bitflags" 7 | version = "1.3.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 10 | 11 | [[package]] 12 | name = "defmt" 13 | version = "1.0.1" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78" 16 | dependencies = [ 17 | "bitflags", 18 | "defmt-macros", 19 | ] 20 | 21 | [[package]] 22 | name = "defmt-macros" 23 | version = "1.0.1" 24 | source = "registry+https://github.com/rust-lang/crates.io-index" 25 | checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e" 26 | dependencies = [ 27 | "defmt-parser", 28 | "proc-macro-error2", 29 | "proc-macro2", 30 | "quote", 31 | "syn", 32 | ] 33 | 34 | [[package]] 35 | name = "defmt-parser" 36 | version = "1.0.0" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" 39 | dependencies = [ 40 | "thiserror", 41 | ] 42 | 43 | [[package]] 44 | name = "embedded-storage" 45 | version = "0.3.1" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032" 48 | 49 | [[package]] 50 | name = "esp-hal-ota" 51 | version = "0.4.5" 52 | dependencies = [ 53 | "defmt", 54 | "embedded-storage", 55 | "esp32", 56 | "esp32c2", 57 | "esp32c3", 58 | "esp32c6", 59 | "esp32h2", 60 | "esp32s2", 61 | "esp32s3", 62 | "log", 63 | ] 64 | 65 | [[package]] 66 | name = "esp32" 67 | version = "0.39.0" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "b76170a463d18f888a1ad258031901036fd827a9ef126733053ba5f8739fb0c8" 70 | dependencies = [ 71 | "vcell", 72 | ] 73 | 74 | [[package]] 75 | name = "esp32c2" 76 | version = "0.28.0" 77 | source = "registry+https://github.com/rust-lang/crates.io-index" 78 | checksum = "e62cf8932966b8d445b6f1832977b468178f0a84effb2e9fda89f60c24d45aa3" 79 | dependencies = [ 80 | "vcell", 81 | ] 82 | 83 | [[package]] 84 | name = "esp32c3" 85 | version = "0.31.0" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "356af3771d0d6536c735bf71136594f4d1cbb506abf6e0c51a6639e9bf4e7988" 88 | dependencies = [ 89 | "vcell", 90 | ] 91 | 92 | [[package]] 93 | name = "esp32c6" 94 | version = "0.22.0" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | checksum = "8f5e511df672d79cd63365c92045135e01ba952b6bddd25b660baff5e1110f6b" 97 | dependencies = [ 98 | "vcell", 99 | ] 100 | 101 | [[package]] 102 | name = "esp32h2" 103 | version = "0.18.0" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | checksum = "ed4a50bbd1380931e095e0973b9b12f782a9c481f2edf1f7c42e7eb4ff736d6d" 106 | dependencies = [ 107 | "vcell", 108 | ] 109 | 110 | [[package]] 111 | name = "esp32s2" 112 | version = "0.30.0" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | checksum = "98574d4c577fbe888fe3e6df7fc80d25a05624d9998f7d7de1500ae21fcca78f" 115 | dependencies = [ 116 | "vcell", 117 | ] 118 | 119 | [[package]] 120 | name = "esp32s3" 121 | version = "0.34.0" 122 | source = "registry+https://github.com/rust-lang/crates.io-index" 123 | checksum = "1810d8ee4845ef87542af981e38eb80ab531d0ef1061e1486014ab7af74c337a" 124 | dependencies = [ 125 | "vcell", 126 | ] 127 | 128 | [[package]] 129 | name = "log" 130 | version = "0.4.28" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" 133 | 134 | [[package]] 135 | name = "proc-macro-error-attr2" 136 | version = "2.0.0" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" 139 | dependencies = [ 140 | "proc-macro2", 141 | "quote", 142 | ] 143 | 144 | [[package]] 145 | name = "proc-macro-error2" 146 | version = "2.0.1" 147 | source = "registry+https://github.com/rust-lang/crates.io-index" 148 | checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" 149 | dependencies = [ 150 | "proc-macro-error-attr2", 151 | "proc-macro2", 152 | "quote", 153 | "syn", 154 | ] 155 | 156 | [[package]] 157 | name = "proc-macro2" 158 | version = "1.0.95" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" 161 | dependencies = [ 162 | "unicode-ident", 163 | ] 164 | 165 | [[package]] 166 | name = "quote" 167 | version = "1.0.40" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 170 | dependencies = [ 171 | "proc-macro2", 172 | ] 173 | 174 | [[package]] 175 | name = "syn" 176 | version = "2.0.104" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" 179 | dependencies = [ 180 | "proc-macro2", 181 | "quote", 182 | "unicode-ident", 183 | ] 184 | 185 | [[package]] 186 | name = "thiserror" 187 | version = "2.0.12" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" 190 | dependencies = [ 191 | "thiserror-impl", 192 | ] 193 | 194 | [[package]] 195 | name = "thiserror-impl" 196 | version = "2.0.12" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" 199 | dependencies = [ 200 | "proc-macro2", 201 | "quote", 202 | "syn", 203 | ] 204 | 205 | [[package]] 206 | name = "unicode-ident" 207 | version = "1.0.18" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 210 | 211 | [[package]] 212 | name = "vcell" 213 | version = "0.1.3" 214 | source = "registry+https://github.com/rust-lang/crates.io-index" 215 | checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" 216 | -------------------------------------------------------------------------------- /examples/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | #![feature(type_alias_impl_trait)] 4 | 5 | extern crate alloc; 6 | use core::str::FromStr; 7 | use embassy_executor::Spawner; 8 | use embassy_net::{Config, Runner, Stack, StackResources, tcp::TcpSocket}; 9 | use embassy_time::{Duration, Timer}; 10 | use esp_backtrace as _; 11 | use esp_hal::timer::timg::TimerGroup; 12 | use esp_hal_ota::Ota; 13 | use esp_radio::{ 14 | Controller, 15 | wifi::{ClientConfig, ModeConfig, WifiController, WifiDevice, WifiEvent, WifiStaState}, 16 | }; 17 | use esp_storage::FlashStorage; 18 | 19 | const WIFI_SSID: &'static str = env!("SSID"); 20 | const WIFI_PSK: &'static str = env!("PSK"); 21 | const OTA_SERVER_IP: &'static str = env!("OTA_IP"); 22 | 23 | const RX_BUFFER_SIZE: usize = 16384; 24 | const TX_BUFFER_SIZE: usize = 16384; 25 | static mut TX_BUFF: [u8; TX_BUFFER_SIZE] = [0; TX_BUFFER_SIZE]; 26 | static mut RX_BUFF: [u8; RX_BUFFER_SIZE] = [0; RX_BUFFER_SIZE]; 27 | 28 | macro_rules! mk_static { 29 | ($t:ty,$val:expr) => {{ 30 | static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new(); 31 | #[deny(unused_attributes)] 32 | let x = STATIC_CELL.uninit().write(($val)); 33 | x 34 | }}; 35 | } 36 | 37 | esp_bootloader_esp_idf::esp_app_desc!(); 38 | 39 | #[esp_rtos::main] 40 | async fn main(spawner: Spawner) { 41 | #[cfg(not(feature = "esp32"))] 42 | { 43 | esp_alloc::heap_allocator!(size: 150 * 1024); 44 | } 45 | 46 | #[cfg(feature = "esp32")] 47 | { 48 | static mut HEAP: core::mem::MaybeUninit<[u8; 30 * 1024]> = core::mem::MaybeUninit::uninit(); 49 | 50 | #[unsafe(link_section = ".dram2_uninit")] 51 | static mut HEAP2: core::mem::MaybeUninit<[u8; 64 * 1024]> = 52 | core::mem::MaybeUninit::uninit(); 53 | 54 | unsafe { 55 | #[allow(static_mut_refs)] 56 | esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new( 57 | HEAP.as_mut_ptr() as *mut u8, 58 | core::mem::size_of_val(&*core::ptr::addr_of!(HEAP)), 59 | esp_alloc::MemoryCapability::Internal.into(), 60 | )); 61 | 62 | #[allow(static_mut_refs)] 63 | esp_alloc::HEAP.add_region(esp_alloc::HeapRegion::new( 64 | HEAP2.as_mut_ptr() as *mut u8, 65 | core::mem::size_of_val(&*core::ptr::addr_of!(HEAP2)), 66 | esp_alloc::MemoryCapability::Internal.into(), 67 | )); 68 | } 69 | } 70 | 71 | let peripherals = esp_hal::init(esp_hal::Config::default()); 72 | //let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); 73 | 74 | esp_println::logger::init_logger_from_env(); 75 | //log::set_max_level(log::LevelFilter::Info); // only for esp32s3?? 76 | 77 | let timg0 = TimerGroup::new(peripherals.TIMG0); 78 | 79 | #[cfg(any(feature = "esp32s3", feature = "esp32"))] 80 | esp_rtos::start(timg0.timer0); 81 | 82 | #[cfg(feature = "esp32c3")] 83 | let software_interrupt = 84 | esp_hal::interrupt::software::SoftwareInterruptControl::new(peripherals.SW_INTERRUPT); 85 | 86 | #[cfg(feature = "esp32c3")] 87 | esp_rtos::start(timg0.timer0, software_interrupt.software_interrupt0); 88 | 89 | let init = &*mk_static!(Controller<'static>, esp_radio::init().unwrap()); 90 | 91 | let wifi = peripherals.WIFI; 92 | let (controller, interfaces) = esp_radio::wifi::new(&init, wifi, Default::default()).unwrap(); 93 | 94 | let config = Config::dhcpv4(Default::default()); 95 | let seed = 69420; 96 | 97 | let (stack, runner) = embassy_net::new( 98 | interfaces.sta, 99 | config, 100 | { 101 | static STATIC_CELL: static_cell::StaticCell> = 102 | static_cell::StaticCell::new(); 103 | STATIC_CELL.uninit().write(StackResources::<3>::new()) 104 | }, 105 | seed, 106 | ); 107 | 108 | spawner 109 | .spawn(connection(controller, stack)) 110 | .expect("connection spawn"); 111 | spawner.spawn(net_task(runner)).expect("net task spawn"); 112 | 113 | // mark ota partition valid 114 | { 115 | let mut ota = Ota::new(FlashStorage::new(unsafe { 116 | peripherals.FLASH.clone_unchecked() 117 | })) 118 | .expect("Cannot create ota"); 119 | _ = ota.ota_mark_app_valid(); //do not unwrap here if using factory/test partition 120 | } 121 | 122 | loop { 123 | log::info!("Wait for wifi!"); 124 | Timer::after(Duration::from_secs(1)).await; 125 | 126 | if let Some(config) = stack.config_v4() { 127 | log::info!("Got IP: {}", config.address); 128 | break; 129 | } 130 | } 131 | 132 | let mut socket = unsafe { 133 | TcpSocket::new( 134 | stack, 135 | &mut *core::ptr::addr_of_mut!(RX_BUFF), 136 | &mut *core::ptr::addr_of_mut!(TX_BUFF), 137 | ) 138 | }; 139 | 140 | let ip = embassy_net::IpEndpoint::from_str(OTA_SERVER_IP).expect("Wrong ip addr"); 141 | socket.connect(ip).await.expect("Cannot connect!"); 142 | let mut ota_buff = [0; 4096 * 2]; 143 | socket 144 | .read(&mut ota_buff[..4]) 145 | .await 146 | .expect("Cannot read firmware size!"); 147 | let flash_size = u32::from_le_bytes(ota_buff[..4].try_into().unwrap()); 148 | 149 | socket 150 | .read(&mut ota_buff[..4]) 151 | .await 152 | .expect("Cannot read target crc!"); 153 | let target_crc = u32::from_le_bytes(ota_buff[..4].try_into().unwrap()); 154 | 155 | log::info!("flash_size: {flash_size}"); 156 | log::info!("target_crc: {target_crc}"); 157 | 158 | let mut ota = Ota::new(FlashStorage::new(unsafe { 159 | peripherals.FLASH.clone_unchecked() 160 | })) 161 | .expect("Cannot create ota"); 162 | ota.ota_begin(flash_size, target_crc).unwrap(); 163 | 164 | let mut bytes_read: usize = 0; 165 | loop { 166 | let bytes_to_read = 8192.min(flash_size - bytes_read as u32); 167 | let res = read_exact(&mut socket, &mut ota_buff[..bytes_to_read as usize]).await; 168 | if let Ok(_) = res { 169 | bytes_read += bytes_to_read as usize; 170 | if bytes_to_read == 0 { 171 | break; 172 | } 173 | 174 | let res = ota.ota_write_chunk(&ota_buff[..bytes_to_read as usize]); 175 | _ = socket.write(&[0]).await; 176 | 177 | match res { 178 | Ok(true) => { 179 | let res = ota.ota_flush(false, true); 180 | if let Err(e) = res { 181 | log::error!("Ota flush error: {e:?}"); 182 | break; 183 | } 184 | 185 | log::info!("Ota OK! Rebooting in 1s!"); 186 | Timer::after_millis(1000).await; 187 | esp_hal::system::software_reset(); 188 | } 189 | Err(e) => { 190 | log::error!("Ota write error: {e:?}"); 191 | break; 192 | } 193 | _ => {} 194 | } 195 | } 196 | 197 | log::info!("Progress: {}%", (ota.get_ota_progress() * 100.0) as u8); 198 | } 199 | 200 | loop { 201 | log::info!("bump"); 202 | Timer::after_millis(15000).await; 203 | } 204 | } 205 | 206 | #[embassy_executor::task] 207 | async fn connection(mut controller: WifiController<'static>, stack: Stack<'static>) { 208 | log::info!("start connection task"); 209 | log::info!("Device capabilities: {:?}", controller.capabilities()); 210 | loop { 211 | if esp_radio::wifi::sta_state() == WifiStaState::Connected { 212 | // wait until we're no longer connected 213 | controller.wait_for_event(WifiEvent::StaDisconnected).await; 214 | Timer::after(Duration::from_millis(5000)).await 215 | } 216 | if !matches!(controller.is_started(), Ok(true)) { 217 | let client_config = ModeConfig::Client( 218 | ClientConfig::default() 219 | .with_ssid(WIFI_SSID.try_into().expect("Wifi ssid parse")) 220 | .with_password(WIFI_PSK.try_into().expect("Wifi psk parse")), 221 | ); 222 | controller.set_config(&client_config).unwrap(); 223 | log::info!("Starting wifi"); 224 | controller.start_async().await.unwrap(); 225 | log::info!("Wifi started!"); 226 | } 227 | log::info!("About to connect..."); 228 | 229 | match controller.connect_async().await { 230 | Ok(_) => { 231 | log::info!("Wifi connected!"); 232 | 233 | loop { 234 | if stack.is_link_up() { 235 | break; 236 | } 237 | Timer::after(Duration::from_millis(500)).await; 238 | } 239 | } 240 | Err(e) => { 241 | log::info!("Failed to connect to wifi: {e:?}"); 242 | Timer::after(Duration::from_millis(5000)).await 243 | } 244 | } 245 | } 246 | } 247 | 248 | #[embassy_executor::task] 249 | async fn net_task(mut runner: Runner<'static, WifiDevice<'static>>) { 250 | runner.run().await 251 | } 252 | 253 | pub async fn read_exact( 254 | socket: &mut TcpSocket<'_>, 255 | mut buf: &mut [u8], 256 | ) -> Result<(), embassy_net::tcp::Error> { 257 | while !buf.is_empty() { 258 | match socket.read(buf).await { 259 | Ok(0) => return Err(embassy_net::tcp::Error::ConnectionReset), 260 | Ok(n) => { 261 | buf = &mut buf[n..]; 262 | } 263 | Err(e) => return Err(e), 264 | } 265 | } 266 | Ok(()) 267 | } 268 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![cfg_attr(any(feature = "esp32", feature = "esp32s2"), feature(concat_idents))] 3 | #![cfg_attr(feature = "esp32", feature(asm_experimental_arch))] 4 | #![doc = include_str!("../README.md")] 5 | 6 | #[macro_use] 7 | mod logging; 8 | 9 | use embedded_storage::{ReadStorage, Storage}; 10 | pub use structs::*; 11 | 12 | pub mod crc32; 13 | pub mod helpers; 14 | pub mod mmu_hal; 15 | pub mod mmu_ll; 16 | pub mod structs; 17 | 18 | const PART_OFFSET: u32 = 0x8000; 19 | const PART_SIZE: u32 = 0xc00; 20 | const FIRST_OTA_PART_SUBTYPE: u8 = 0x10; 21 | const OTA_VERIFY_READ_SIZE: usize = 256; 22 | 23 | pub struct Ota 24 | where 25 | S: ReadStorage + Storage, 26 | { 27 | flash: S, 28 | 29 | progress: Option, 30 | pinfo: PartitionInfo, 31 | } 32 | 33 | pub struct ProgressDetails { 34 | pub remaining: u32, 35 | pub last_crc: u32, 36 | } 37 | 38 | #[derive(Debug)] 39 | pub struct OtaConfiguratuion { 40 | partition_table_offset: u32, 41 | } 42 | impl OtaConfiguratuion { 43 | /// Create default configuration of the [`Ota`] process. 44 | /// 45 | /// Notably this uses the default partition table offset of `0x8000` 46 | pub const fn new() -> Self { 47 | Self { 48 | partition_table_offset: PART_OFFSET, 49 | } 50 | } 51 | 52 | /// Set custom partition table offset 53 | pub const fn with_partition_table_offset(self, partition_table_offset: u32) -> Self { 54 | Self { 55 | partition_table_offset, 56 | ..self 57 | } 58 | } 59 | } 60 | impl Default for OtaConfiguratuion { 61 | fn default() -> Self { 62 | Self::new() 63 | } 64 | } 65 | 66 | impl Ota 67 | where 68 | S: ReadStorage + Storage, 69 | { 70 | pub fn new(flash: S) -> Result { 71 | Self::with_configuration(flash, OtaConfiguratuion::new()) 72 | } 73 | 74 | pub fn with_configuration(mut flash: S, config: OtaConfiguratuion) -> Result { 75 | let pinfo = Self::read_partitions(&mut flash, config.partition_table_offset)?; 76 | if pinfo.ota_partitions_count < 2 { 77 | error!("Not enough OTA partitions! (>= 2)"); 78 | 79 | return Err(OtaError::NotEnoughPartitions); 80 | } 81 | 82 | Ok(Ota { 83 | flash, 84 | progress: None, 85 | pinfo, 86 | }) 87 | } 88 | 89 | fn get_partitions(&self) -> &[(u32, u32)] { 90 | &self.pinfo.ota_partitions[..self.pinfo.ota_partitions_count] 91 | } 92 | 93 | /// To begin ota update (need to provide flash size) 94 | pub fn ota_begin(&mut self, size: u32, target_crc: u32) -> Result<()> { 95 | let next_part = self.get_next_ota_partition().unwrap_or(0); 96 | 97 | let ota_offset = self.get_partitions()[next_part].0; 98 | self.progress = Some(FlashProgress { 99 | last_crc: 0, 100 | flash_size: size, 101 | remaining: size, 102 | flash_offset: ota_offset, 103 | target_partition: next_part, 104 | target_crc, 105 | }); 106 | 107 | Ok(()) 108 | } 109 | 110 | /// Resumes an OTA update after progress has been lost 111 | pub fn ota_resume( 112 | &mut self, 113 | flash_size: u32, 114 | remaining: u32, 115 | target_crc: u32, 116 | last_crc: u32, 117 | verify_crc: bool, 118 | ) -> Result<()> { 119 | let next_part = self.get_next_ota_partition().unwrap_or(0); 120 | let ota_offset = self.get_partitions()[next_part].0; 121 | 122 | if verify_crc { 123 | let mut calc_crc = 0; 124 | let mut bytes = [0; OTA_VERIFY_READ_SIZE]; 125 | let mut written = flash_size - remaining; 126 | let mut partition_offset = ota_offset; 127 | 128 | loop { 129 | let n = written.min(OTA_VERIFY_READ_SIZE as u32); 130 | if n == 0 { 131 | break; 132 | } 133 | 134 | _ = self.flash.read(partition_offset, &mut bytes[..n as usize]); 135 | partition_offset += n; 136 | written -= n; 137 | 138 | calc_crc = crc32::calc_crc32(&bytes[..n as usize], calc_crc); 139 | } 140 | 141 | if calc_crc != last_crc { 142 | return Err(OtaError::WrongCRC); 143 | } 144 | } 145 | 146 | self.progress = Some(FlashProgress { 147 | last_crc, 148 | flash_size, 149 | remaining, 150 | flash_offset: ota_offset + (flash_size - remaining), 151 | target_partition: next_part, 152 | target_crc, 153 | }); 154 | 155 | Ok(()) 156 | } 157 | 158 | /// Returns progress details to save for resumption later 159 | pub fn get_progress_details(&self) -> Option { 160 | if self.progress.is_none() { 161 | warn!("[OTA] Cannot get progress details!"); 162 | 163 | return None; 164 | } 165 | 166 | let progress = self.progress.as_ref().unwrap(); 167 | Some(ProgressDetails { 168 | remaining: progress.remaining, 169 | last_crc: progress.last_crc, 170 | }) 171 | } 172 | 173 | /// Returns ota progress in f32 (0..1) 174 | pub fn get_ota_progress(&self) -> f32 { 175 | if self.progress.is_none() { 176 | warn!("[OTA] Cannot get ota progress! Seems like update wasn't started yet."); 177 | 178 | return 0.0; 179 | } 180 | 181 | let progress = self.progress.as_ref().unwrap(); 182 | (progress.flash_size - progress.remaining) as f32 / progress.flash_size as f32 183 | } 184 | 185 | /// Writes next firmware chunk 186 | pub fn ota_write_chunk(&mut self, chunk: &[u8]) -> Result { 187 | let progress = self.progress.as_mut().ok_or(OtaError::OtaNotStarted)?; 188 | 189 | if progress.remaining == 0 { 190 | return Ok(true); 191 | } 192 | 193 | let write_size = chunk.len() as u32; 194 | let write_size = write_size.min(progress.remaining) as usize; 195 | 196 | self.flash 197 | .write(progress.flash_offset, &chunk[..write_size]) 198 | .map_err(|_| OtaError::FlashRWError)?; 199 | 200 | debug!( 201 | "[OTA] Wrote {} bytes to ota partition at 0x{:x}", 202 | write_size, progress.flash_offset 203 | ); 204 | 205 | progress.last_crc = crc32::calc_crc32(&chunk[..write_size], progress.last_crc); 206 | 207 | progress.flash_offset += write_size as u32; 208 | progress.remaining -= write_size as u32; 209 | Ok(progress.remaining == 0) 210 | } 211 | 212 | /// verify - should it read flash and check crc 213 | /// rollback - if rollbacks enable (will set ota_state to ESP_OTA_IMG_NEW) 214 | pub fn ota_flush(&mut self, verify: bool, rollback: bool) -> Result<()> { 215 | if verify && !self.ota_verify()? { 216 | error!("[OTA] Verify failed! Not flushing..."); 217 | 218 | return Err(OtaError::OtaVerifyError); 219 | } 220 | 221 | let progress = self.progress.clone().ok_or(OtaError::OtaNotStarted)?; 222 | 223 | if progress.target_crc != progress.last_crc { 224 | warn!("[OTA] Calculated crc: {}", progress.last_crc); 225 | warn!("[OTA] Target crc: {}", progress.target_crc); 226 | error!("[OTA] Crc check failed! Cant finish ota update..."); 227 | 228 | return Err(OtaError::WrongCRC); 229 | } 230 | 231 | let img_state = match rollback { 232 | true => OtaImgState::EspOtaImgNew, 233 | false => OtaImgState::EspOtaImgUndefined, 234 | }; 235 | 236 | self.set_target_ota_boot_partition(progress.target_partition, img_state); 237 | Ok(()) 238 | } 239 | 240 | /// It reads written flash and checks crc 241 | pub fn ota_verify(&mut self) -> Result { 242 | let progress = self.progress.clone().ok_or(OtaError::OtaNotStarted)?; 243 | 244 | let mut calc_crc = 0; 245 | let mut bytes = [0; OTA_VERIFY_READ_SIZE]; 246 | 247 | let mut partition_offset = self.pinfo.ota_partitions[progress.target_partition].0; 248 | let mut remaining = progress.flash_size; 249 | 250 | loop { 251 | let n = remaining.min(OTA_VERIFY_READ_SIZE as u32); 252 | if n == 0 { 253 | break; 254 | } 255 | 256 | _ = self.flash.read(partition_offset, &mut bytes[..n as usize]); 257 | partition_offset += n; 258 | remaining -= n; 259 | 260 | calc_crc = crc32::calc_crc32(&bytes[..n as usize], calc_crc); 261 | } 262 | 263 | Ok(calc_crc == progress.target_crc) 264 | } 265 | 266 | /// Sets ota boot target partition 267 | pub fn set_target_ota_boot_partition(&mut self, target: usize, state: OtaImgState) { 268 | let (slot1, slot2) = self.get_ota_boot_entries(); 269 | let (seq1, seq2) = (slot1.seq, slot2.seq); 270 | 271 | let mut target_seq = seq1.max(seq2); 272 | while helpers::seq_to_part(target_seq, self.pinfo.ota_partitions_count) != target 273 | || target_seq == 0 274 | { 275 | target_seq += 1; 276 | } 277 | 278 | let flash = &mut self.flash; 279 | let target_crc = crc32::calc_crc32(&target_seq.to_le_bytes(), 0xFFFFFFFF); 280 | if seq1 > seq2 { 281 | let offset = self.pinfo.otadata_offset + (self.pinfo.otadata_size >> 1); 282 | 283 | _ = flash.write(offset, &target_seq.to_le_bytes()); 284 | _ = flash.write(offset + 32 - 4 - 4, &(state as u32).to_le_bytes()); 285 | _ = flash.write(offset + 32 - 4, &target_crc.to_le_bytes()); 286 | } else { 287 | _ = flash.write(self.pinfo.otadata_offset, &target_seq.to_le_bytes()); 288 | _ = flash.write( 289 | self.pinfo.otadata_offset + 32 - 4 - 4, 290 | &(state as u32).to_le_bytes(), 291 | ); 292 | _ = flash.write( 293 | self.pinfo.otadata_offset + 32 - 4, 294 | &target_crc.to_le_bytes(), 295 | ); 296 | } 297 | } 298 | 299 | pub fn set_ota_state(&mut self, slot: u8, state: OtaImgState) -> Result<()> { 300 | let offset = match slot { 301 | 1 => self.pinfo.otadata_offset, 302 | 2 => self.pinfo.otadata_offset + (self.pinfo.otadata_size >> 1), 303 | _ => { 304 | error!("Use slot1 or slot2!"); 305 | return Err(OtaError::CannotFindCurrentBootPartition); 306 | } 307 | }; 308 | 309 | _ = self 310 | .flash 311 | .write(offset + 32 - 4 - 4, &(state as u32).to_le_bytes()); 312 | 313 | Ok(()) 314 | } 315 | 316 | /// Returns current OTA boot sequences 317 | /// 318 | /// NOTE: if crc doesn't match, it returns 0 for that seq 319 | /// NOTE: [Entry struct (link to .h file)](https://github.com/espressif/esp-idf/blob/master/components/bootloader_support/include/esp_flash_partitions.h#L66) 320 | pub fn get_ota_boot_entries(&mut self) -> (EspOtaSelectEntry, EspOtaSelectEntry) { 321 | let mut bytes = [0; 32]; 322 | _ = self.flash.read(self.pinfo.otadata_offset, &mut bytes); 323 | let mut slot1: EspOtaSelectEntry = 324 | unsafe { core::ptr::read(bytes.as_ptr() as *const EspOtaSelectEntry) }; 325 | slot1.check_crc(); 326 | 327 | _ = self.flash.read( 328 | self.pinfo.otadata_offset + (self.pinfo.otadata_size >> 1), 329 | &mut bytes, 330 | ); 331 | let mut slot2: EspOtaSelectEntry = 332 | unsafe { core::ptr::read(bytes.as_ptr() as *const EspOtaSelectEntry) }; 333 | slot2.check_crc(); 334 | 335 | (slot1, slot2) 336 | } 337 | 338 | /// Returns currently booted partition index 339 | pub fn get_currently_booted_partition(&self) -> Option { 340 | mmu_hal::esp_get_current_running_partition(self.get_partitions()) 341 | } 342 | 343 | /// BUG: this wont work if user has ota partitions not starting from ota0 344 | /// or if user skips some ota partitions: ota0, ota2, ota3... 345 | pub fn get_next_ota_partition(&self) -> Option { 346 | let curr_part = mmu_hal::esp_get_current_running_partition(self.get_partitions()); 347 | curr_part.map(|next_part| (next_part + 1) % self.pinfo.ota_partitions_count) 348 | } 349 | 350 | fn get_current_slot(&mut self) -> Result<(u8, EspOtaSelectEntry)> { 351 | let (slot1, slot2) = self.get_ota_boot_entries(); 352 | let current_partition = self 353 | .get_currently_booted_partition() 354 | .ok_or(OtaError::CannotFindCurrentBootPartition)?; 355 | 356 | let slot1_part = helpers::seq_to_part(slot1.seq, self.pinfo.ota_partitions_count); 357 | let slot2_part = helpers::seq_to_part(slot2.seq, self.pinfo.ota_partitions_count); 358 | if current_partition == slot1_part { 359 | return Ok((1, slot1)); 360 | } else if current_partition == slot2_part { 361 | return Ok((2, slot2)); 362 | } 363 | 364 | Err(OtaError::CannotFindCurrentBootPartition) 365 | } 366 | 367 | pub fn get_ota_image_state(&mut self) -> Result { 368 | let (slot1, slot2) = self.get_ota_boot_entries(); 369 | let current_partition = self 370 | .get_currently_booted_partition() 371 | .ok_or(OtaError::CannotFindCurrentBootPartition)?; 372 | 373 | let slot1_part = helpers::seq_to_part(slot1.seq, self.pinfo.ota_partitions_count); 374 | let slot2_part = helpers::seq_to_part(slot2.seq, self.pinfo.ota_partitions_count); 375 | if current_partition == slot1_part { 376 | return Ok(slot1.ota_state); 377 | } else if current_partition == slot2_part { 378 | return Ok(slot2.ota_state); 379 | } 380 | 381 | Err(OtaError::CannotFindCurrentBootPartition) 382 | } 383 | 384 | pub fn ota_mark_app_valid(&mut self) -> Result<()> { 385 | let (current_slot_nmb, current_slot) = self.get_current_slot()?; 386 | if current_slot.ota_state != OtaImgState::EspOtaImgValid { 387 | self.set_ota_state(current_slot_nmb, OtaImgState::EspOtaImgValid)?; 388 | 389 | info!("Marked current slot as valid!"); 390 | } 391 | 392 | Ok(()) 393 | } 394 | 395 | pub fn ota_mark_app_invalid_rollback(&mut self) -> Result<()> { 396 | let (current_slot_nmb, current_slot) = self.get_current_slot()?; 397 | if current_slot.ota_state != OtaImgState::EspOtaImgValid { 398 | self.set_ota_state(current_slot_nmb, OtaImgState::EspOtaImgInvalid)?; 399 | 400 | info!("Marked current slot as invalid!"); 401 | } 402 | 403 | Ok(()) 404 | } 405 | 406 | fn read_partitions(flash: &mut S, partition_table_offset: u32) -> Result { 407 | let mut tmp_pinfo = PartitionInfo { 408 | ota_partitions: [(0, 0); 16], 409 | ota_partitions_count: 0, 410 | otadata_size: 0, 411 | otadata_offset: 0, 412 | }; 413 | 414 | let mut bytes = [0xFF; 32]; 415 | let mut last_ota_part: i8 = -1; 416 | for read_offset in (0..PART_SIZE).step_by(32) { 417 | _ = flash.read(partition_table_offset + read_offset, &mut bytes); 418 | if bytes == [0xFF; 32] { 419 | break; 420 | } 421 | 422 | let magic = &bytes[0..2]; 423 | if magic != [0xAA, 0x50] { 424 | continue; 425 | } 426 | 427 | let p_type = &bytes[2]; 428 | let p_subtype = &bytes[3]; 429 | let p_offset = u32::from_le_bytes(bytes[4..8].try_into().unwrap()); 430 | let p_size = u32::from_le_bytes(bytes[8..12].try_into().unwrap()); 431 | //let p_name = core::str::from_utf8(&bytes[12..28]).unwrap(); 432 | //let p_flags = u32::from_le_bytes(bytes[28..32].try_into().unwrap()); 433 | //log::info!("{magic:?} {p_type} {p_subtype} {p_offset} {p_size} {p_name} {p_flags}"); 434 | 435 | if *p_type == 0 && *p_subtype >= FIRST_OTA_PART_SUBTYPE { 436 | let ota_part_idx = *p_subtype - FIRST_OTA_PART_SUBTYPE; 437 | if ota_part_idx as i8 - last_ota_part != 1 { 438 | return Err(OtaError::WrongOTAPArtitionOrder); 439 | } 440 | 441 | last_ota_part = ota_part_idx as i8; 442 | tmp_pinfo.ota_partitions[tmp_pinfo.ota_partitions_count] = (p_offset, p_size); 443 | tmp_pinfo.ota_partitions_count += 1; 444 | } else if *p_type == 1 && *p_subtype == 0 { 445 | //otadata 446 | tmp_pinfo.otadata_offset = p_offset; 447 | tmp_pinfo.otadata_size = p_size; 448 | } 449 | } 450 | 451 | Ok(tmp_pinfo) 452 | } 453 | } 454 | -------------------------------------------------------------------------------- /examples/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "allocator-api2" 7 | version = "0.3.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "78200ac3468a57d333cd0ea5dd398e25111194dcacd49208afca95c629a6311d" 10 | 11 | [[package]] 12 | name = "anyhow" 13 | version = "1.0.98" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" 16 | 17 | [[package]] 18 | name = "autocfg" 19 | version = "1.4.0" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 22 | 23 | [[package]] 24 | name = "base64" 25 | version = "0.13.1" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" 28 | 29 | [[package]] 30 | name = "bitfield" 31 | version = "0.19.1" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "db1bcd90f88eabbf0cadbfb87a45bceeaebcd3b4bc9e43da379cd2ef0162590d" 34 | dependencies = [ 35 | "bitfield-macros", 36 | ] 37 | 38 | [[package]] 39 | name = "bitfield-macros" 40 | version = "0.19.1" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "3787a07661997bfc05dd3431e379c0188573f78857080cf682e1393ab8e4d64c" 43 | dependencies = [ 44 | "proc-macro2", 45 | "quote", 46 | "syn 2.0.101", 47 | ] 48 | 49 | [[package]] 50 | name = "bitflags" 51 | version = "1.3.2" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 54 | 55 | [[package]] 56 | name = "bitflags" 57 | version = "2.9.1" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" 60 | 61 | [[package]] 62 | name = "block-buffer" 63 | version = "0.10.4" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 66 | dependencies = [ 67 | "generic-array", 68 | ] 69 | 70 | [[package]] 71 | name = "bt-hci" 72 | version = "0.6.0" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "bb938a3b4c5cc6c2409275bad789c0346a0495fa071a0acc5d72b9bd3175a2f7" 75 | dependencies = [ 76 | "btuuid", 77 | "embassy-sync 0.7.2", 78 | "embedded-io 0.6.1", 79 | "embedded-io-async 0.6.1", 80 | "futures-intrusive", 81 | "heapless 0.8.0", 82 | ] 83 | 84 | [[package]] 85 | name = "btuuid" 86 | version = "0.1.0" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | checksum = "b0acfef8a77a02866e04f7e2ad3f4c7b32d575696c49c4bbad742b4aecb8e4a3" 89 | 90 | [[package]] 91 | name = "bytemuck" 92 | version = "1.24.0" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" 95 | 96 | [[package]] 97 | name = "byteorder" 98 | version = "1.5.0" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 101 | 102 | [[package]] 103 | name = "cfg-if" 104 | version = "1.0.1" 105 | source = "registry+https://github.com/rust-lang/crates.io-index" 106 | checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" 107 | 108 | [[package]] 109 | name = "const-default" 110 | version = "1.0.0" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | checksum = "0b396d1f76d455557e1218ec8066ae14bba60b4b36ecd55577ba979f5db7ecaa" 113 | 114 | [[package]] 115 | name = "cpufeatures" 116 | version = "0.2.17" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" 119 | dependencies = [ 120 | "libc", 121 | ] 122 | 123 | [[package]] 124 | name = "critical-section" 125 | version = "1.2.0" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" 128 | 129 | [[package]] 130 | name = "crypto-common" 131 | version = "0.1.6" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 134 | dependencies = [ 135 | "generic-array", 136 | "typenum", 137 | ] 138 | 139 | [[package]] 140 | name = "darling" 141 | version = "0.20.11" 142 | source = "registry+https://github.com/rust-lang/crates.io-index" 143 | checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" 144 | dependencies = [ 145 | "darling_core", 146 | "darling_macro", 147 | ] 148 | 149 | [[package]] 150 | name = "darling_core" 151 | version = "0.20.11" 152 | source = "registry+https://github.com/rust-lang/crates.io-index" 153 | checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" 154 | dependencies = [ 155 | "fnv", 156 | "ident_case", 157 | "proc-macro2", 158 | "quote", 159 | "strsim", 160 | "syn 2.0.101", 161 | ] 162 | 163 | [[package]] 164 | name = "darling_macro" 165 | version = "0.20.11" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" 168 | dependencies = [ 169 | "darling_core", 170 | "quote", 171 | "syn 2.0.101", 172 | ] 173 | 174 | [[package]] 175 | name = "delegate" 176 | version = "0.13.3" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | checksum = "b9b6483c2bbed26f97861cf57651d4f2b731964a28cd2257f934a4b452480d21" 179 | dependencies = [ 180 | "proc-macro2", 181 | "quote", 182 | "syn 2.0.101", 183 | ] 184 | 185 | [[package]] 186 | name = "digest" 187 | version = "0.10.7" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 190 | dependencies = [ 191 | "block-buffer", 192 | "crypto-common", 193 | ] 194 | 195 | [[package]] 196 | name = "document-features" 197 | version = "0.2.11" 198 | source = "registry+https://github.com/rust-lang/crates.io-index" 199 | checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" 200 | dependencies = [ 201 | "litrs", 202 | ] 203 | 204 | [[package]] 205 | name = "dotenvy" 206 | version = "0.15.7" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" 209 | 210 | [[package]] 211 | name = "embassy-embedded-hal" 212 | version = "0.5.0" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | checksum = "554e3e840696f54b4c9afcf28a0f24da431c927f4151040020416e7393d6d0d8" 215 | dependencies = [ 216 | "embassy-futures", 217 | "embassy-hal-internal", 218 | "embassy-sync 0.7.2", 219 | "embedded-hal 0.2.7", 220 | "embedded-hal 1.0.0", 221 | "embedded-hal-async", 222 | "embedded-storage", 223 | "embedded-storage-async", 224 | "nb 1.1.0", 225 | ] 226 | 227 | [[package]] 228 | name = "embassy-executor" 229 | version = "0.9.1" 230 | source = "registry+https://github.com/rust-lang/crates.io-index" 231 | checksum = "06070468370195e0e86f241c8e5004356d696590a678d47d6676795b2e439c6b" 232 | dependencies = [ 233 | "critical-section", 234 | "document-features", 235 | "embassy-executor-macros", 236 | "embassy-executor-timer-queue", 237 | ] 238 | 239 | [[package]] 240 | name = "embassy-executor-macros" 241 | version = "0.7.0" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | checksum = "dfdddc3a04226828316bf31393b6903ee162238576b1584ee2669af215d55472" 244 | dependencies = [ 245 | "darling", 246 | "proc-macro2", 247 | "quote", 248 | "syn 2.0.101", 249 | ] 250 | 251 | [[package]] 252 | name = "embassy-executor-timer-queue" 253 | version = "0.1.0" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | checksum = "2fc328bf943af66b80b98755db9106bf7e7471b0cf47dc8559cd9a6be504cc9c" 256 | 257 | [[package]] 258 | name = "embassy-futures" 259 | version = "0.1.2" 260 | source = "registry+https://github.com/rust-lang/crates.io-index" 261 | checksum = "dc2d050bdc5c21e0862a89256ed8029ae6c290a93aecefc73084b3002cdebb01" 262 | 263 | [[package]] 264 | name = "embassy-hal-internal" 265 | version = "0.3.0" 266 | source = "registry+https://github.com/rust-lang/crates.io-index" 267 | checksum = "95285007a91b619dc9f26ea8f55452aa6c60f7115a4edc05085cd2bd3127cd7a" 268 | dependencies = [ 269 | "num-traits", 270 | ] 271 | 272 | [[package]] 273 | name = "embassy-net" 274 | version = "0.7.1" 275 | source = "registry+https://github.com/rust-lang/crates.io-index" 276 | checksum = "0558a231a47e7d4a06a28b5278c92e860f1200f24821d2f365a2f40fe3f3c7b2" 277 | dependencies = [ 278 | "document-features", 279 | "embassy-net-driver", 280 | "embassy-sync 0.7.2", 281 | "embassy-time", 282 | "embedded-io-async 0.6.1", 283 | "embedded-nal-async", 284 | "heapless 0.8.0", 285 | "managed", 286 | "smoltcp", 287 | ] 288 | 289 | [[package]] 290 | name = "embassy-net-driver" 291 | version = "0.2.0" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "524eb3c489760508f71360112bca70f6e53173e6fe48fc5f0efd0f5ab217751d" 294 | 295 | [[package]] 296 | name = "embassy-sync" 297 | version = "0.6.2" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | checksum = "8d2c8cdff05a7a51ba0087489ea44b0b1d97a296ca6b1d6d1a33ea7423d34049" 300 | dependencies = [ 301 | "cfg-if", 302 | "critical-section", 303 | "embedded-io-async 0.6.1", 304 | "futures-sink", 305 | "futures-util", 306 | "heapless 0.8.0", 307 | ] 308 | 309 | [[package]] 310 | name = "embassy-sync" 311 | version = "0.7.2" 312 | source = "registry+https://github.com/rust-lang/crates.io-index" 313 | checksum = "73974a3edbd0bd286759b3d483540f0ebef705919a5f56f4fc7709066f71689b" 314 | dependencies = [ 315 | "cfg-if", 316 | "critical-section", 317 | "embedded-io-async 0.6.1", 318 | "futures-core", 319 | "futures-sink", 320 | "heapless 0.8.0", 321 | ] 322 | 323 | [[package]] 324 | name = "embassy-time" 325 | version = "0.5.0" 326 | source = "registry+https://github.com/rust-lang/crates.io-index" 327 | checksum = "f4fa65b9284d974dad7a23bb72835c4ec85c0b540d86af7fc4098c88cff51d65" 328 | dependencies = [ 329 | "cfg-if", 330 | "critical-section", 331 | "document-features", 332 | "embassy-time-driver", 333 | "embedded-hal 0.2.7", 334 | "embedded-hal 1.0.0", 335 | "embedded-hal-async", 336 | "futures-core", 337 | ] 338 | 339 | [[package]] 340 | name = "embassy-time-driver" 341 | version = "0.2.1" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "a0a244c7dc22c8d0289379c8d8830cae06bb93d8f990194d0de5efb3b5ae7ba6" 344 | dependencies = [ 345 | "document-features", 346 | ] 347 | 348 | [[package]] 349 | name = "embassy-time-queue-utils" 350 | version = "0.3.0" 351 | source = "registry+https://github.com/rust-lang/crates.io-index" 352 | checksum = "80e2ee86063bd028a420a5fb5898c18c87a8898026da1d4c852af2c443d0a454" 353 | dependencies = [ 354 | "embassy-executor-timer-queue", 355 | "heapless 0.8.0", 356 | ] 357 | 358 | [[package]] 359 | name = "embassy-usb-driver" 360 | version = "0.2.0" 361 | source = "registry+https://github.com/rust-lang/crates.io-index" 362 | checksum = "17119855ccc2d1f7470a39756b12068454ae27a3eabb037d940b5c03d9c77b7a" 363 | dependencies = [ 364 | "embedded-io-async 0.6.1", 365 | ] 366 | 367 | [[package]] 368 | name = "embassy-usb-synopsys-otg" 369 | version = "0.3.1" 370 | source = "registry+https://github.com/rust-lang/crates.io-index" 371 | checksum = "288751f8eaa44a5cf2613f13cee0ca8e06e6638cb96e897e6834702c79084b23" 372 | dependencies = [ 373 | "critical-section", 374 | "embassy-sync 0.7.2", 375 | "embassy-usb-driver", 376 | ] 377 | 378 | [[package]] 379 | name = "embedded-can" 380 | version = "0.4.1" 381 | source = "registry+https://github.com/rust-lang/crates.io-index" 382 | checksum = "e9d2e857f87ac832df68fa498d18ddc679175cf3d2e4aa893988e5601baf9438" 383 | dependencies = [ 384 | "nb 1.1.0", 385 | ] 386 | 387 | [[package]] 388 | name = "embedded-hal" 389 | version = "0.2.7" 390 | source = "registry+https://github.com/rust-lang/crates.io-index" 391 | checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" 392 | dependencies = [ 393 | "nb 0.1.3", 394 | "void", 395 | ] 396 | 397 | [[package]] 398 | name = "embedded-hal" 399 | version = "1.0.0" 400 | source = "registry+https://github.com/rust-lang/crates.io-index" 401 | checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" 402 | 403 | [[package]] 404 | name = "embedded-hal-async" 405 | version = "1.0.0" 406 | source = "registry+https://github.com/rust-lang/crates.io-index" 407 | checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" 408 | dependencies = [ 409 | "embedded-hal 1.0.0", 410 | ] 411 | 412 | [[package]] 413 | name = "embedded-io" 414 | version = "0.6.1" 415 | source = "registry+https://github.com/rust-lang/crates.io-index" 416 | checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" 417 | 418 | [[package]] 419 | name = "embedded-io" 420 | version = "0.7.1" 421 | source = "registry+https://github.com/rust-lang/crates.io-index" 422 | checksum = "9eb1aa714776b75c7e67e1da744b81a129b3ff919c8712b5e1b32252c1f07cc7" 423 | 424 | [[package]] 425 | name = "embedded-io-async" 426 | version = "0.6.1" 427 | source = "registry+https://github.com/rust-lang/crates.io-index" 428 | checksum = "3ff09972d4073aa8c299395be75161d582e7629cd663171d62af73c8d50dba3f" 429 | dependencies = [ 430 | "embedded-io 0.6.1", 431 | ] 432 | 433 | [[package]] 434 | name = "embedded-io-async" 435 | version = "0.7.0" 436 | source = "registry+https://github.com/rust-lang/crates.io-index" 437 | checksum = "2564b9f813c544241430e147d8bc454815ef9ac998878d30cc3055449f7fd4c0" 438 | dependencies = [ 439 | "embedded-io 0.7.1", 440 | ] 441 | 442 | [[package]] 443 | name = "embedded-nal" 444 | version = "0.9.0" 445 | source = "registry+https://github.com/rust-lang/crates.io-index" 446 | checksum = "c56a28be191a992f28f178ec338a0bf02f63d7803244add736d026a471e6ed77" 447 | dependencies = [ 448 | "nb 1.1.0", 449 | ] 450 | 451 | [[package]] 452 | name = "embedded-nal-async" 453 | version = "0.8.0" 454 | source = "registry+https://github.com/rust-lang/crates.io-index" 455 | checksum = "76959917cd2b86f40a98c28dd5624eddd1fa69d746241c8257eac428d83cb211" 456 | dependencies = [ 457 | "embedded-io-async 0.6.1", 458 | "embedded-nal", 459 | ] 460 | 461 | [[package]] 462 | name = "embedded-storage" 463 | version = "0.3.1" 464 | source = "registry+https://github.com/rust-lang/crates.io-index" 465 | checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032" 466 | 467 | [[package]] 468 | name = "embedded-storage-async" 469 | version = "0.4.1" 470 | source = "registry+https://github.com/rust-lang/crates.io-index" 471 | checksum = "1763775e2323b7d5f0aa6090657f5e21cfa02ede71f5dc40eead06d64dcd15cc" 472 | dependencies = [ 473 | "embedded-storage", 474 | ] 475 | 476 | [[package]] 477 | name = "enumset" 478 | version = "1.1.6" 479 | source = "registry+https://github.com/rust-lang/crates.io-index" 480 | checksum = "11a6b7c3d347de0a9f7bfd2f853be43fe32fa6fac30c70f6d6d67a1e936b87ee" 481 | dependencies = [ 482 | "enumset_derive", 483 | ] 484 | 485 | [[package]] 486 | name = "enumset_derive" 487 | version = "0.11.0" 488 | source = "registry+https://github.com/rust-lang/crates.io-index" 489 | checksum = "6da3ea9e1d1a3b1593e15781f930120e72aa7501610b2f82e5b6739c72e8eac5" 490 | dependencies = [ 491 | "darling", 492 | "proc-macro2", 493 | "quote", 494 | "syn 2.0.101", 495 | ] 496 | 497 | [[package]] 498 | name = "equivalent" 499 | version = "1.0.2" 500 | source = "registry+https://github.com/rust-lang/crates.io-index" 501 | checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 502 | 503 | [[package]] 504 | name = "esp-alloc" 505 | version = "0.9.0" 506 | source = "registry+https://github.com/rust-lang/crates.io-index" 507 | checksum = "641e43d6a60244429117ef2fa7a47182120c7561336ea01f6fb08d634f46bae1" 508 | dependencies = [ 509 | "allocator-api2", 510 | "cfg-if", 511 | "document-features", 512 | "enumset", 513 | "esp-config", 514 | "esp-sync", 515 | "linked_list_allocator", 516 | "rlsf", 517 | ] 518 | 519 | [[package]] 520 | name = "esp-backtrace" 521 | version = "0.18.0" 522 | source = "registry+https://github.com/rust-lang/crates.io-index" 523 | checksum = "fdd8a541e17aa485d82df547f03c77b89f78cb110f59dea67cc90733d67e3678" 524 | dependencies = [ 525 | "cfg-if", 526 | "document-features", 527 | "esp-config", 528 | "esp-metadata-generated", 529 | "esp-println", 530 | "heapless 0.9.1", 531 | "riscv", 532 | "semihosting", 533 | "xtensa-lx", 534 | ] 535 | 536 | [[package]] 537 | name = "esp-bootloader-esp-idf" 538 | version = "0.3.0" 539 | source = "registry+https://github.com/rust-lang/crates.io-index" 540 | checksum = "c319c4a24fb44ef4c5f9854ff3dc6010eb8f15a6613d024227aa2355e3f6a334" 541 | dependencies = [ 542 | "cfg-if", 543 | "document-features", 544 | "embedded-storage", 545 | "esp-config", 546 | "esp-rom-sys", 547 | "jiff", 548 | "log", 549 | "strum", 550 | ] 551 | 552 | [[package]] 553 | name = "esp-config" 554 | version = "0.6.0" 555 | source = "registry+https://github.com/rust-lang/crates.io-index" 556 | checksum = "289fde78fff1ff500e81efbdf958b1dae1614eacc61cc5560b0a3e03a25f266e" 557 | dependencies = [ 558 | "document-features", 559 | "esp-metadata-generated", 560 | "serde", 561 | "serde_yaml", 562 | "somni-expr", 563 | ] 564 | 565 | [[package]] 566 | name = "esp-hal" 567 | version = "1.0.0-rc.1" 568 | source = "registry+https://github.com/rust-lang/crates.io-index" 569 | checksum = "f75242d788e67fc7ce51308019c0ff5d5103f989721577bb566b02710ef1ba79" 570 | dependencies = [ 571 | "bitfield", 572 | "bitflags 2.9.1", 573 | "bytemuck", 574 | "cfg-if", 575 | "critical-section", 576 | "delegate", 577 | "digest", 578 | "document-features", 579 | "embassy-embedded-hal", 580 | "embassy-futures", 581 | "embassy-sync 0.7.2", 582 | "embassy-usb-driver", 583 | "embassy-usb-synopsys-otg", 584 | "embedded-can", 585 | "embedded-hal 1.0.0", 586 | "embedded-hal-async", 587 | "embedded-io 0.6.1", 588 | "embedded-io 0.7.1", 589 | "embedded-io-async 0.6.1", 590 | "embedded-io-async 0.7.0", 591 | "enumset", 592 | "esp-config", 593 | "esp-hal-procmacros", 594 | "esp-metadata-generated", 595 | "esp-riscv-rt", 596 | "esp-rom-sys", 597 | "esp-sync", 598 | "esp-synopsys-usb-otg", 599 | "esp32", 600 | "esp32c2", 601 | "esp32c3", 602 | "esp32c6", 603 | "esp32h2", 604 | "esp32s2", 605 | "esp32s3", 606 | "fugit", 607 | "instability", 608 | "nb 1.1.0", 609 | "paste", 610 | "portable-atomic", 611 | "rand_core 0.6.4", 612 | "rand_core 0.9.3", 613 | "riscv", 614 | "sha1", 615 | "sha2", 616 | "strum", 617 | "ufmt-write", 618 | "xtensa-lx", 619 | "xtensa-lx-rt", 620 | ] 621 | 622 | [[package]] 623 | name = "esp-hal-ota" 624 | version = "0.4.5" 625 | dependencies = [ 626 | "embedded-storage", 627 | "esp32", 628 | "esp32c3", 629 | "esp32s3", 630 | "log", 631 | ] 632 | 633 | [[package]] 634 | name = "esp-hal-ota-example" 635 | version = "0.1.0" 636 | dependencies = [ 637 | "dotenvy", 638 | "embassy-executor", 639 | "embassy-net", 640 | "embassy-time", 641 | "esp-alloc", 642 | "esp-backtrace", 643 | "esp-bootloader-esp-idf", 644 | "esp-hal", 645 | "esp-hal-ota", 646 | "esp-println", 647 | "esp-radio", 648 | "esp-rtos", 649 | "esp-storage", 650 | "log", 651 | "static_cell", 652 | ] 653 | 654 | [[package]] 655 | name = "esp-hal-procmacros" 656 | version = "0.20.0" 657 | source = "registry+https://github.com/rust-lang/crates.io-index" 658 | checksum = "9fd82a6506fb08d53a1086d165d92f085717aa9c59e67ac87a9e6f8acdcf6897" 659 | dependencies = [ 660 | "document-features", 661 | "object", 662 | "proc-macro-crate", 663 | "proc-macro2", 664 | "quote", 665 | "syn 2.0.101", 666 | "termcolor", 667 | ] 668 | 669 | [[package]] 670 | name = "esp-metadata-generated" 671 | version = "0.2.0" 672 | source = "registry+https://github.com/rust-lang/crates.io-index" 673 | checksum = "b18b1787dd3adea642fb529dd83fe558a08ace365bbaede4643a8959992900f4" 674 | 675 | [[package]] 676 | name = "esp-phy" 677 | version = "0.1.0" 678 | source = "registry+https://github.com/rust-lang/crates.io-index" 679 | checksum = "62199c3e50eefcf53b8f3c690946582a124f7137b45bd1b14eb4b90a3fec2dd7" 680 | dependencies = [ 681 | "cfg-if", 682 | "document-features", 683 | "esp-config", 684 | "esp-hal", 685 | "esp-metadata-generated", 686 | "esp-sync", 687 | "esp-wifi-sys", 688 | ] 689 | 690 | [[package]] 691 | name = "esp-println" 692 | version = "0.16.0" 693 | source = "registry+https://github.com/rust-lang/crates.io-index" 694 | checksum = "6dcd18cbb132db6eb30d7c96bd831c3b6916894210f4528321f69fa66178b331" 695 | dependencies = [ 696 | "document-features", 697 | "esp-metadata-generated", 698 | "esp-sync", 699 | "log", 700 | "portable-atomic", 701 | ] 702 | 703 | [[package]] 704 | name = "esp-radio" 705 | version = "0.16.0" 706 | source = "registry+https://github.com/rust-lang/crates.io-index" 707 | checksum = "d83744f57d19a7190a538ad42025da7f53940c3aca71cbcd92275095d671e254" 708 | dependencies = [ 709 | "allocator-api2", 710 | "bt-hci", 711 | "cfg-if", 712 | "document-features", 713 | "embassy-net-driver", 714 | "embedded-io 0.6.1", 715 | "embedded-io 0.7.1", 716 | "embedded-io-async 0.6.1", 717 | "embedded-io-async 0.7.0", 718 | "enumset", 719 | "esp-alloc", 720 | "esp-config", 721 | "esp-hal", 722 | "esp-hal-procmacros", 723 | "esp-metadata-generated", 724 | "esp-phy", 725 | "esp-radio-rtos-driver", 726 | "esp-sync", 727 | "esp-wifi-sys", 728 | "heapless 0.9.1", 729 | "instability", 730 | "num-derive", 731 | "num-traits", 732 | "portable-atomic", 733 | "portable_atomic_enum", 734 | "xtensa-lx-rt", 735 | ] 736 | 737 | [[package]] 738 | name = "esp-radio-rtos-driver" 739 | version = "0.1.0" 740 | source = "registry+https://github.com/rust-lang/crates.io-index" 741 | checksum = "ab031e544f6bc086c2d7aba89276e6a47ce6bb5614ae3c88a1c12a4ab4f8f25c" 742 | 743 | [[package]] 744 | name = "esp-riscv-rt" 745 | version = "0.13.0" 746 | source = "registry+https://github.com/rust-lang/crates.io-index" 747 | checksum = "502744a5b1e7268d27fd2a4e56ad45efe42ead517d6c517a6961540de949b0ee" 748 | dependencies = [ 749 | "document-features", 750 | "riscv", 751 | "riscv-rt", 752 | ] 753 | 754 | [[package]] 755 | name = "esp-rom-sys" 756 | version = "0.1.2" 757 | source = "registry+https://github.com/rust-lang/crates.io-index" 758 | checksum = "01bafc39f59d56610b38ed0f63b16abeb8b357b8f546507d0d6c50c1a494f530" 759 | dependencies = [ 760 | "cfg-if", 761 | "document-features", 762 | "esp-metadata-generated", 763 | ] 764 | 765 | [[package]] 766 | name = "esp-rtos" 767 | version = "0.1.0" 768 | source = "registry+https://github.com/rust-lang/crates.io-index" 769 | checksum = "7844233ccdf92eaf4134c08c56c1b4a874f7d59e6249c579e912ecc6c9312fda" 770 | dependencies = [ 771 | "allocator-api2", 772 | "cfg-if", 773 | "document-features", 774 | "embassy-executor", 775 | "embassy-sync 0.7.2", 776 | "embassy-time-driver", 777 | "embassy-time-queue-utils", 778 | "esp-config", 779 | "esp-hal", 780 | "esp-hal-procmacros", 781 | "esp-metadata-generated", 782 | "esp-radio-rtos-driver", 783 | "esp-sync", 784 | "portable-atomic", 785 | ] 786 | 787 | [[package]] 788 | name = "esp-storage" 789 | version = "0.8.0" 790 | source = "registry+https://github.com/rust-lang/crates.io-index" 791 | checksum = "4ac4c20d28188fc31ad34008ad3a94dd7d828e5fef0c83c265bdb7dac168d512" 792 | dependencies = [ 793 | "document-features", 794 | "embedded-storage", 795 | "esp-hal", 796 | "esp-hal-procmacros", 797 | "esp-metadata-generated", 798 | "esp-rom-sys", 799 | "esp-sync", 800 | ] 801 | 802 | [[package]] 803 | name = "esp-sync" 804 | version = "0.1.0" 805 | source = "registry+https://github.com/rust-lang/crates.io-index" 806 | checksum = "b977b028ae5959f0b2daf6602a1d751723b2d329c7251daf869ad382c8ed1543" 807 | dependencies = [ 808 | "cfg-if", 809 | "document-features", 810 | "embassy-sync 0.6.2", 811 | "embassy-sync 0.7.2", 812 | "esp-metadata-generated", 813 | "riscv", 814 | "xtensa-lx", 815 | ] 816 | 817 | [[package]] 818 | name = "esp-synopsys-usb-otg" 819 | version = "0.4.2" 820 | source = "registry+https://github.com/rust-lang/crates.io-index" 821 | checksum = "8938451cb19032f13365328ea66ab38c8d16deecdf322067442297110eb74468" 822 | dependencies = [ 823 | "critical-section", 824 | "embedded-hal 0.2.7", 825 | "ral-registers", 826 | "usb-device", 827 | "vcell", 828 | ] 829 | 830 | [[package]] 831 | name = "esp-wifi-sys" 832 | version = "0.8.1" 833 | source = "registry+https://github.com/rust-lang/crates.io-index" 834 | checksum = "89b6544f6f0cb86169d1f93ba2101a8d50358a040c5043676ed86b793e09b12c" 835 | dependencies = [ 836 | "anyhow", 837 | ] 838 | 839 | [[package]] 840 | name = "esp32" 841 | version = "0.39.0" 842 | source = "registry+https://github.com/rust-lang/crates.io-index" 843 | checksum = "b76170a463d18f888a1ad258031901036fd827a9ef126733053ba5f8739fb0c8" 844 | dependencies = [ 845 | "critical-section", 846 | "vcell", 847 | ] 848 | 849 | [[package]] 850 | name = "esp32c2" 851 | version = "0.28.0" 852 | source = "registry+https://github.com/rust-lang/crates.io-index" 853 | checksum = "e62cf8932966b8d445b6f1832977b468178f0a84effb2e9fda89f60c24d45aa3" 854 | dependencies = [ 855 | "critical-section", 856 | "vcell", 857 | ] 858 | 859 | [[package]] 860 | name = "esp32c3" 861 | version = "0.31.0" 862 | source = "registry+https://github.com/rust-lang/crates.io-index" 863 | checksum = "356af3771d0d6536c735bf71136594f4d1cbb506abf6e0c51a6639e9bf4e7988" 864 | dependencies = [ 865 | "critical-section", 866 | "vcell", 867 | ] 868 | 869 | [[package]] 870 | name = "esp32c6" 871 | version = "0.22.0" 872 | source = "registry+https://github.com/rust-lang/crates.io-index" 873 | checksum = "8f5e511df672d79cd63365c92045135e01ba952b6bddd25b660baff5e1110f6b" 874 | dependencies = [ 875 | "critical-section", 876 | "vcell", 877 | ] 878 | 879 | [[package]] 880 | name = "esp32h2" 881 | version = "0.18.0" 882 | source = "registry+https://github.com/rust-lang/crates.io-index" 883 | checksum = "ed4a50bbd1380931e095e0973b9b12f782a9c481f2edf1f7c42e7eb4ff736d6d" 884 | dependencies = [ 885 | "critical-section", 886 | "vcell", 887 | ] 888 | 889 | [[package]] 890 | name = "esp32s2" 891 | version = "0.30.0" 892 | source = "registry+https://github.com/rust-lang/crates.io-index" 893 | checksum = "98574d4c577fbe888fe3e6df7fc80d25a05624d9998f7d7de1500ae21fcca78f" 894 | dependencies = [ 895 | "critical-section", 896 | "vcell", 897 | ] 898 | 899 | [[package]] 900 | name = "esp32s3" 901 | version = "0.34.0" 902 | source = "registry+https://github.com/rust-lang/crates.io-index" 903 | checksum = "1810d8ee4845ef87542af981e38eb80ab531d0ef1061e1486014ab7af74c337a" 904 | dependencies = [ 905 | "critical-section", 906 | "vcell", 907 | ] 908 | 909 | [[package]] 910 | name = "fnv" 911 | version = "1.0.7" 912 | source = "registry+https://github.com/rust-lang/crates.io-index" 913 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 914 | 915 | [[package]] 916 | name = "fugit" 917 | version = "0.3.7" 918 | source = "registry+https://github.com/rust-lang/crates.io-index" 919 | checksum = "17186ad64927d5ac8f02c1e77ccefa08ccd9eaa314d5a4772278aa204a22f7e7" 920 | dependencies = [ 921 | "gcd", 922 | ] 923 | 924 | [[package]] 925 | name = "futures-core" 926 | version = "0.3.31" 927 | source = "registry+https://github.com/rust-lang/crates.io-index" 928 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 929 | 930 | [[package]] 931 | name = "futures-intrusive" 932 | version = "0.5.0" 933 | source = "registry+https://github.com/rust-lang/crates.io-index" 934 | checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" 935 | dependencies = [ 936 | "futures-core", 937 | "lock_api", 938 | ] 939 | 940 | [[package]] 941 | name = "futures-sink" 942 | version = "0.3.31" 943 | source = "registry+https://github.com/rust-lang/crates.io-index" 944 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 945 | 946 | [[package]] 947 | name = "futures-task" 948 | version = "0.3.31" 949 | source = "registry+https://github.com/rust-lang/crates.io-index" 950 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 951 | 952 | [[package]] 953 | name = "futures-util" 954 | version = "0.3.31" 955 | source = "registry+https://github.com/rust-lang/crates.io-index" 956 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 957 | dependencies = [ 958 | "futures-core", 959 | "futures-task", 960 | "pin-project-lite", 961 | "pin-utils", 962 | ] 963 | 964 | [[package]] 965 | name = "gcd" 966 | version = "2.3.0" 967 | source = "registry+https://github.com/rust-lang/crates.io-index" 968 | checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" 969 | 970 | [[package]] 971 | name = "generic-array" 972 | version = "0.14.7" 973 | source = "registry+https://github.com/rust-lang/crates.io-index" 974 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 975 | dependencies = [ 976 | "typenum", 977 | "version_check", 978 | ] 979 | 980 | [[package]] 981 | name = "hash32" 982 | version = "0.3.1" 983 | source = "registry+https://github.com/rust-lang/crates.io-index" 984 | checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" 985 | dependencies = [ 986 | "byteorder", 987 | ] 988 | 989 | [[package]] 990 | name = "hashbrown" 991 | version = "0.15.3" 992 | source = "registry+https://github.com/rust-lang/crates.io-index" 993 | checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" 994 | 995 | [[package]] 996 | name = "heapless" 997 | version = "0.8.0" 998 | source = "registry+https://github.com/rust-lang/crates.io-index" 999 | checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" 1000 | dependencies = [ 1001 | "hash32", 1002 | "stable_deref_trait", 1003 | ] 1004 | 1005 | [[package]] 1006 | name = "heapless" 1007 | version = "0.9.1" 1008 | source = "registry+https://github.com/rust-lang/crates.io-index" 1009 | checksum = "b1edcd5a338e64688fbdcb7531a846cfd3476a54784dcb918a0844682bc7ada5" 1010 | dependencies = [ 1011 | "hash32", 1012 | "stable_deref_trait", 1013 | ] 1014 | 1015 | [[package]] 1016 | name = "heck" 1017 | version = "0.5.0" 1018 | source = "registry+https://github.com/rust-lang/crates.io-index" 1019 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 1020 | 1021 | [[package]] 1022 | name = "ident_case" 1023 | version = "1.0.1" 1024 | source = "registry+https://github.com/rust-lang/crates.io-index" 1025 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 1026 | 1027 | [[package]] 1028 | name = "indexmap" 1029 | version = "2.11.4" 1030 | source = "registry+https://github.com/rust-lang/crates.io-index" 1031 | checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" 1032 | dependencies = [ 1033 | "equivalent", 1034 | "hashbrown", 1035 | ] 1036 | 1037 | [[package]] 1038 | name = "indoc" 1039 | version = "2.0.6" 1040 | source = "registry+https://github.com/rust-lang/crates.io-index" 1041 | checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" 1042 | 1043 | [[package]] 1044 | name = "instability" 1045 | version = "0.3.9" 1046 | source = "registry+https://github.com/rust-lang/crates.io-index" 1047 | checksum = "435d80800b936787d62688c927b6490e887c7ef5ff9ce922c6c6050fca75eb9a" 1048 | dependencies = [ 1049 | "darling", 1050 | "indoc", 1051 | "proc-macro2", 1052 | "quote", 1053 | "syn 2.0.101", 1054 | ] 1055 | 1056 | [[package]] 1057 | name = "itoa" 1058 | version = "1.0.15" 1059 | source = "registry+https://github.com/rust-lang/crates.io-index" 1060 | checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 1061 | 1062 | [[package]] 1063 | name = "jiff" 1064 | version = "0.2.15" 1065 | source = "registry+https://github.com/rust-lang/crates.io-index" 1066 | checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" 1067 | dependencies = [ 1068 | "jiff-static", 1069 | "log", 1070 | "portable-atomic", 1071 | "portable-atomic-util", 1072 | "serde", 1073 | ] 1074 | 1075 | [[package]] 1076 | name = "jiff-static" 1077 | version = "0.2.15" 1078 | source = "registry+https://github.com/rust-lang/crates.io-index" 1079 | checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" 1080 | dependencies = [ 1081 | "proc-macro2", 1082 | "quote", 1083 | "syn 2.0.101", 1084 | ] 1085 | 1086 | [[package]] 1087 | name = "libc" 1088 | version = "0.2.177" 1089 | source = "registry+https://github.com/rust-lang/crates.io-index" 1090 | checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" 1091 | 1092 | [[package]] 1093 | name = "linked_list_allocator" 1094 | version = "0.10.5" 1095 | source = "registry+https://github.com/rust-lang/crates.io-index" 1096 | checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" 1097 | 1098 | [[package]] 1099 | name = "litrs" 1100 | version = "0.4.1" 1101 | source = "registry+https://github.com/rust-lang/crates.io-index" 1102 | checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" 1103 | 1104 | [[package]] 1105 | name = "lock_api" 1106 | version = "0.4.13" 1107 | source = "registry+https://github.com/rust-lang/crates.io-index" 1108 | checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" 1109 | dependencies = [ 1110 | "autocfg", 1111 | "scopeguard", 1112 | ] 1113 | 1114 | [[package]] 1115 | name = "log" 1116 | version = "0.4.28" 1117 | source = "registry+https://github.com/rust-lang/crates.io-index" 1118 | checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" 1119 | 1120 | [[package]] 1121 | name = "managed" 1122 | version = "0.8.0" 1123 | source = "registry+https://github.com/rust-lang/crates.io-index" 1124 | checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d" 1125 | 1126 | [[package]] 1127 | name = "memchr" 1128 | version = "2.7.4" 1129 | source = "registry+https://github.com/rust-lang/crates.io-index" 1130 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 1131 | 1132 | [[package]] 1133 | name = "nb" 1134 | version = "0.1.3" 1135 | source = "registry+https://github.com/rust-lang/crates.io-index" 1136 | checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" 1137 | dependencies = [ 1138 | "nb 1.1.0", 1139 | ] 1140 | 1141 | [[package]] 1142 | name = "nb" 1143 | version = "1.1.0" 1144 | source = "registry+https://github.com/rust-lang/crates.io-index" 1145 | checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" 1146 | 1147 | [[package]] 1148 | name = "num-derive" 1149 | version = "0.4.2" 1150 | source = "registry+https://github.com/rust-lang/crates.io-index" 1151 | checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" 1152 | dependencies = [ 1153 | "proc-macro2", 1154 | "quote", 1155 | "syn 2.0.101", 1156 | ] 1157 | 1158 | [[package]] 1159 | name = "num-traits" 1160 | version = "0.2.19" 1161 | source = "registry+https://github.com/rust-lang/crates.io-index" 1162 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 1163 | dependencies = [ 1164 | "autocfg", 1165 | ] 1166 | 1167 | [[package]] 1168 | name = "object" 1169 | version = "0.37.3" 1170 | source = "registry+https://github.com/rust-lang/crates.io-index" 1171 | checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" 1172 | dependencies = [ 1173 | "memchr", 1174 | ] 1175 | 1176 | [[package]] 1177 | name = "paste" 1178 | version = "1.0.15" 1179 | source = "registry+https://github.com/rust-lang/crates.io-index" 1180 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 1181 | 1182 | [[package]] 1183 | name = "pin-project-lite" 1184 | version = "0.2.16" 1185 | source = "registry+https://github.com/rust-lang/crates.io-index" 1186 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 1187 | 1188 | [[package]] 1189 | name = "pin-utils" 1190 | version = "0.1.0" 1191 | source = "registry+https://github.com/rust-lang/crates.io-index" 1192 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1193 | 1194 | [[package]] 1195 | name = "portable-atomic" 1196 | version = "1.11.0" 1197 | source = "registry+https://github.com/rust-lang/crates.io-index" 1198 | checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" 1199 | 1200 | [[package]] 1201 | name = "portable-atomic-util" 1202 | version = "0.2.4" 1203 | source = "registry+https://github.com/rust-lang/crates.io-index" 1204 | checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" 1205 | dependencies = [ 1206 | "portable-atomic", 1207 | ] 1208 | 1209 | [[package]] 1210 | name = "portable_atomic_enum" 1211 | version = "0.3.1" 1212 | source = "registry+https://github.com/rust-lang/crates.io-index" 1213 | checksum = "30d48f60c43e0120bb2bb48589a16d4bed2f4b911be41e299f2d0fc0e0e20885" 1214 | dependencies = [ 1215 | "portable-atomic", 1216 | "portable_atomic_enum_macros", 1217 | ] 1218 | 1219 | [[package]] 1220 | name = "portable_atomic_enum_macros" 1221 | version = "0.2.1" 1222 | source = "registry+https://github.com/rust-lang/crates.io-index" 1223 | checksum = "a33fa6ec7f2047f572d49317cca19c87195de99c6e5b6ee492da701cfe02b053" 1224 | dependencies = [ 1225 | "proc-macro2", 1226 | "quote", 1227 | "syn 2.0.101", 1228 | ] 1229 | 1230 | [[package]] 1231 | name = "proc-macro-crate" 1232 | version = "3.4.0" 1233 | source = "registry+https://github.com/rust-lang/crates.io-index" 1234 | checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" 1235 | dependencies = [ 1236 | "toml_edit", 1237 | ] 1238 | 1239 | [[package]] 1240 | name = "proc-macro2" 1241 | version = "1.0.95" 1242 | source = "registry+https://github.com/rust-lang/crates.io-index" 1243 | checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" 1244 | dependencies = [ 1245 | "unicode-ident", 1246 | ] 1247 | 1248 | [[package]] 1249 | name = "quote" 1250 | version = "1.0.40" 1251 | source = "registry+https://github.com/rust-lang/crates.io-index" 1252 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 1253 | dependencies = [ 1254 | "proc-macro2", 1255 | ] 1256 | 1257 | [[package]] 1258 | name = "ral-registers" 1259 | version = "0.1.3" 1260 | source = "registry+https://github.com/rust-lang/crates.io-index" 1261 | checksum = "46b71a9d9206e8b46714c74255adcaea8b11e0350c1d8456165073c3f75fc81a" 1262 | 1263 | [[package]] 1264 | name = "rand_core" 1265 | version = "0.6.4" 1266 | source = "registry+https://github.com/rust-lang/crates.io-index" 1267 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1268 | 1269 | [[package]] 1270 | name = "rand_core" 1271 | version = "0.9.3" 1272 | source = "registry+https://github.com/rust-lang/crates.io-index" 1273 | checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" 1274 | 1275 | [[package]] 1276 | name = "riscv" 1277 | version = "0.15.0" 1278 | source = "registry+https://github.com/rust-lang/crates.io-index" 1279 | checksum = "b05cfa3f7b30c84536a9025150d44d26b8e1cc20ddf436448d74cd9591eefb25" 1280 | dependencies = [ 1281 | "critical-section", 1282 | "embedded-hal 1.0.0", 1283 | "paste", 1284 | "riscv-macros", 1285 | "riscv-pac", 1286 | ] 1287 | 1288 | [[package]] 1289 | name = "riscv-macros" 1290 | version = "0.3.0" 1291 | source = "registry+https://github.com/rust-lang/crates.io-index" 1292 | checksum = "7d323d13972c1b104aa036bc692cd08b822c8bbf23d79a27c526095856499799" 1293 | dependencies = [ 1294 | "proc-macro2", 1295 | "quote", 1296 | "syn 2.0.101", 1297 | ] 1298 | 1299 | [[package]] 1300 | name = "riscv-pac" 1301 | version = "0.2.0" 1302 | source = "registry+https://github.com/rust-lang/crates.io-index" 1303 | checksum = "8188909339ccc0c68cfb5a04648313f09621e8b87dc03095454f1a11f6c5d436" 1304 | 1305 | [[package]] 1306 | name = "riscv-rt" 1307 | version = "0.16.0" 1308 | source = "registry+https://github.com/rust-lang/crates.io-index" 1309 | checksum = "3d07b9f3a0eff773fc4df11f44ada4fa302e529bff4b7fe7e6a4b98a65ce9174" 1310 | dependencies = [ 1311 | "riscv", 1312 | "riscv-pac", 1313 | "riscv-rt-macros", 1314 | "riscv-target-parser", 1315 | ] 1316 | 1317 | [[package]] 1318 | name = "riscv-rt-macros" 1319 | version = "0.6.0" 1320 | source = "registry+https://github.com/rust-lang/crates.io-index" 1321 | checksum = "15c3138fdd8d128b2d81829842a3e0ce771b3712f7b6318ed1476b0695e7d330" 1322 | dependencies = [ 1323 | "proc-macro2", 1324 | "quote", 1325 | "syn 2.0.101", 1326 | ] 1327 | 1328 | [[package]] 1329 | name = "riscv-target-parser" 1330 | version = "0.1.3" 1331 | source = "registry+https://github.com/rust-lang/crates.io-index" 1332 | checksum = "b1376b15f3ff160e9b1e8ea564ce427f2f6fcf77528cc0a8bf405cb476f9cea7" 1333 | 1334 | [[package]] 1335 | name = "rlsf" 1336 | version = "0.2.1" 1337 | source = "registry+https://github.com/rust-lang/crates.io-index" 1338 | checksum = "222fb240c3286247ecdee6fa5341e7cdad0ffdf8e7e401d9937f2d58482a20bf" 1339 | dependencies = [ 1340 | "cfg-if", 1341 | "const-default", 1342 | "libc", 1343 | "svgbobdoc", 1344 | ] 1345 | 1346 | [[package]] 1347 | name = "rustversion" 1348 | version = "1.0.21" 1349 | source = "registry+https://github.com/rust-lang/crates.io-index" 1350 | checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" 1351 | 1352 | [[package]] 1353 | name = "ryu" 1354 | version = "1.0.20" 1355 | source = "registry+https://github.com/rust-lang/crates.io-index" 1356 | checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" 1357 | 1358 | [[package]] 1359 | name = "scopeguard" 1360 | version = "1.2.0" 1361 | source = "registry+https://github.com/rust-lang/crates.io-index" 1362 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1363 | 1364 | [[package]] 1365 | name = "semihosting" 1366 | version = "0.1.20" 1367 | source = "registry+https://github.com/rust-lang/crates.io-index" 1368 | checksum = "c3e1c7d2b77d80283c750a39c52f1ab4d17234e8f30bca43550f5b2375f41d5f" 1369 | 1370 | [[package]] 1371 | name = "serde" 1372 | version = "1.0.228" 1373 | source = "registry+https://github.com/rust-lang/crates.io-index" 1374 | checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" 1375 | dependencies = [ 1376 | "serde_core", 1377 | "serde_derive", 1378 | ] 1379 | 1380 | [[package]] 1381 | name = "serde_core" 1382 | version = "1.0.228" 1383 | source = "registry+https://github.com/rust-lang/crates.io-index" 1384 | checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" 1385 | dependencies = [ 1386 | "serde_derive", 1387 | ] 1388 | 1389 | [[package]] 1390 | name = "serde_derive" 1391 | version = "1.0.228" 1392 | source = "registry+https://github.com/rust-lang/crates.io-index" 1393 | checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" 1394 | dependencies = [ 1395 | "proc-macro2", 1396 | "quote", 1397 | "syn 2.0.101", 1398 | ] 1399 | 1400 | [[package]] 1401 | name = "serde_yaml" 1402 | version = "0.9.34+deprecated" 1403 | source = "registry+https://github.com/rust-lang/crates.io-index" 1404 | checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" 1405 | dependencies = [ 1406 | "indexmap", 1407 | "itoa", 1408 | "ryu", 1409 | "serde", 1410 | "unsafe-libyaml", 1411 | ] 1412 | 1413 | [[package]] 1414 | name = "sha1" 1415 | version = "0.10.6" 1416 | source = "registry+https://github.com/rust-lang/crates.io-index" 1417 | checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" 1418 | dependencies = [ 1419 | "cfg-if", 1420 | "cpufeatures", 1421 | "digest", 1422 | ] 1423 | 1424 | [[package]] 1425 | name = "sha2" 1426 | version = "0.10.9" 1427 | source = "registry+https://github.com/rust-lang/crates.io-index" 1428 | checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" 1429 | dependencies = [ 1430 | "cfg-if", 1431 | "cpufeatures", 1432 | "digest", 1433 | ] 1434 | 1435 | [[package]] 1436 | name = "smoltcp" 1437 | version = "0.12.0" 1438 | source = "registry+https://github.com/rust-lang/crates.io-index" 1439 | checksum = "dad095989c1533c1c266d9b1e8d70a1329dd3723c3edac6d03bbd67e7bf6f4bb" 1440 | dependencies = [ 1441 | "bitflags 1.3.2", 1442 | "byteorder", 1443 | "cfg-if", 1444 | "heapless 0.8.0", 1445 | "managed", 1446 | ] 1447 | 1448 | [[package]] 1449 | name = "somni-expr" 1450 | version = "0.2.0" 1451 | source = "registry+https://github.com/rust-lang/crates.io-index" 1452 | checksum = "3ed9b7648d5e8b2df6c5e49940c54bcdd2b4dd71eafc6e8f1c714eb4581b0f53" 1453 | dependencies = [ 1454 | "somni-parser", 1455 | ] 1456 | 1457 | [[package]] 1458 | name = "somni-parser" 1459 | version = "0.2.0" 1460 | source = "registry+https://github.com/rust-lang/crates.io-index" 1461 | checksum = "74ee90f60ebcade244355ed4ff4077e364b251508c3462af386a9ee96c5a5492" 1462 | 1463 | [[package]] 1464 | name = "stable_deref_trait" 1465 | version = "1.2.0" 1466 | source = "registry+https://github.com/rust-lang/crates.io-index" 1467 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 1468 | 1469 | [[package]] 1470 | name = "static_cell" 1471 | version = "2.1.1" 1472 | source = "registry+https://github.com/rust-lang/crates.io-index" 1473 | checksum = "0530892bb4fa575ee0da4b86f86c667132a94b74bb72160f58ee5a4afec74c23" 1474 | dependencies = [ 1475 | "portable-atomic", 1476 | ] 1477 | 1478 | [[package]] 1479 | name = "strsim" 1480 | version = "0.11.1" 1481 | source = "registry+https://github.com/rust-lang/crates.io-index" 1482 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 1483 | 1484 | [[package]] 1485 | name = "strum" 1486 | version = "0.27.1" 1487 | source = "registry+https://github.com/rust-lang/crates.io-index" 1488 | checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32" 1489 | dependencies = [ 1490 | "strum_macros", 1491 | ] 1492 | 1493 | [[package]] 1494 | name = "strum_macros" 1495 | version = "0.27.1" 1496 | source = "registry+https://github.com/rust-lang/crates.io-index" 1497 | checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8" 1498 | dependencies = [ 1499 | "heck", 1500 | "proc-macro2", 1501 | "quote", 1502 | "rustversion", 1503 | "syn 2.0.101", 1504 | ] 1505 | 1506 | [[package]] 1507 | name = "svgbobdoc" 1508 | version = "0.3.0" 1509 | source = "registry+https://github.com/rust-lang/crates.io-index" 1510 | checksum = "f2c04b93fc15d79b39c63218f15e3fdffaa4c227830686e3b7c5f41244eb3e50" 1511 | dependencies = [ 1512 | "base64", 1513 | "proc-macro2", 1514 | "quote", 1515 | "syn 1.0.109", 1516 | "unicode-width", 1517 | ] 1518 | 1519 | [[package]] 1520 | name = "syn" 1521 | version = "1.0.109" 1522 | source = "registry+https://github.com/rust-lang/crates.io-index" 1523 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 1524 | dependencies = [ 1525 | "proc-macro2", 1526 | "quote", 1527 | "unicode-ident", 1528 | ] 1529 | 1530 | [[package]] 1531 | name = "syn" 1532 | version = "2.0.101" 1533 | source = "registry+https://github.com/rust-lang/crates.io-index" 1534 | checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" 1535 | dependencies = [ 1536 | "proc-macro2", 1537 | "quote", 1538 | "unicode-ident", 1539 | ] 1540 | 1541 | [[package]] 1542 | name = "termcolor" 1543 | version = "1.4.1" 1544 | source = "registry+https://github.com/rust-lang/crates.io-index" 1545 | checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" 1546 | dependencies = [ 1547 | "winapi-util", 1548 | ] 1549 | 1550 | [[package]] 1551 | name = "toml_datetime" 1552 | version = "0.7.3" 1553 | source = "registry+https://github.com/rust-lang/crates.io-index" 1554 | checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" 1555 | dependencies = [ 1556 | "serde_core", 1557 | ] 1558 | 1559 | [[package]] 1560 | name = "toml_edit" 1561 | version = "0.23.7" 1562 | source = "registry+https://github.com/rust-lang/crates.io-index" 1563 | checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" 1564 | dependencies = [ 1565 | "indexmap", 1566 | "toml_datetime", 1567 | "toml_parser", 1568 | "winnow", 1569 | ] 1570 | 1571 | [[package]] 1572 | name = "toml_parser" 1573 | version = "1.0.4" 1574 | source = "registry+https://github.com/rust-lang/crates.io-index" 1575 | checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" 1576 | dependencies = [ 1577 | "winnow", 1578 | ] 1579 | 1580 | [[package]] 1581 | name = "typenum" 1582 | version = "1.18.0" 1583 | source = "registry+https://github.com/rust-lang/crates.io-index" 1584 | checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" 1585 | 1586 | [[package]] 1587 | name = "ufmt-write" 1588 | version = "0.1.0" 1589 | source = "registry+https://github.com/rust-lang/crates.io-index" 1590 | checksum = "e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69" 1591 | 1592 | [[package]] 1593 | name = "unicode-ident" 1594 | version = "1.0.18" 1595 | source = "registry+https://github.com/rust-lang/crates.io-index" 1596 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 1597 | 1598 | [[package]] 1599 | name = "unicode-width" 1600 | version = "0.1.14" 1601 | source = "registry+https://github.com/rust-lang/crates.io-index" 1602 | checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" 1603 | 1604 | [[package]] 1605 | name = "unsafe-libyaml" 1606 | version = "0.2.11" 1607 | source = "registry+https://github.com/rust-lang/crates.io-index" 1608 | checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" 1609 | 1610 | [[package]] 1611 | name = "usb-device" 1612 | version = "0.3.2" 1613 | source = "registry+https://github.com/rust-lang/crates.io-index" 1614 | checksum = "98816b1accafbb09085168b90f27e93d790b4bfa19d883466b5e53315b5f06a6" 1615 | dependencies = [ 1616 | "heapless 0.8.0", 1617 | "portable-atomic", 1618 | ] 1619 | 1620 | [[package]] 1621 | name = "vcell" 1622 | version = "0.1.3" 1623 | source = "registry+https://github.com/rust-lang/crates.io-index" 1624 | checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" 1625 | 1626 | [[package]] 1627 | name = "version_check" 1628 | version = "0.9.5" 1629 | source = "registry+https://github.com/rust-lang/crates.io-index" 1630 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 1631 | 1632 | [[package]] 1633 | name = "void" 1634 | version = "1.0.2" 1635 | source = "registry+https://github.com/rust-lang/crates.io-index" 1636 | checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 1637 | 1638 | [[package]] 1639 | name = "winapi-util" 1640 | version = "0.1.9" 1641 | source = "registry+https://github.com/rust-lang/crates.io-index" 1642 | checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" 1643 | dependencies = [ 1644 | "windows-sys", 1645 | ] 1646 | 1647 | [[package]] 1648 | name = "windows-sys" 1649 | version = "0.59.0" 1650 | source = "registry+https://github.com/rust-lang/crates.io-index" 1651 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 1652 | dependencies = [ 1653 | "windows-targets", 1654 | ] 1655 | 1656 | [[package]] 1657 | name = "windows-targets" 1658 | version = "0.52.6" 1659 | source = "registry+https://github.com/rust-lang/crates.io-index" 1660 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1661 | dependencies = [ 1662 | "windows_aarch64_gnullvm", 1663 | "windows_aarch64_msvc", 1664 | "windows_i686_gnu", 1665 | "windows_i686_gnullvm", 1666 | "windows_i686_msvc", 1667 | "windows_x86_64_gnu", 1668 | "windows_x86_64_gnullvm", 1669 | "windows_x86_64_msvc", 1670 | ] 1671 | 1672 | [[package]] 1673 | name = "windows_aarch64_gnullvm" 1674 | version = "0.52.6" 1675 | source = "registry+https://github.com/rust-lang/crates.io-index" 1676 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1677 | 1678 | [[package]] 1679 | name = "windows_aarch64_msvc" 1680 | version = "0.52.6" 1681 | source = "registry+https://github.com/rust-lang/crates.io-index" 1682 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1683 | 1684 | [[package]] 1685 | name = "windows_i686_gnu" 1686 | version = "0.52.6" 1687 | source = "registry+https://github.com/rust-lang/crates.io-index" 1688 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1689 | 1690 | [[package]] 1691 | name = "windows_i686_gnullvm" 1692 | version = "0.52.6" 1693 | source = "registry+https://github.com/rust-lang/crates.io-index" 1694 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1695 | 1696 | [[package]] 1697 | name = "windows_i686_msvc" 1698 | version = "0.52.6" 1699 | source = "registry+https://github.com/rust-lang/crates.io-index" 1700 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1701 | 1702 | [[package]] 1703 | name = "windows_x86_64_gnu" 1704 | version = "0.52.6" 1705 | source = "registry+https://github.com/rust-lang/crates.io-index" 1706 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1707 | 1708 | [[package]] 1709 | name = "windows_x86_64_gnullvm" 1710 | version = "0.52.6" 1711 | source = "registry+https://github.com/rust-lang/crates.io-index" 1712 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1713 | 1714 | [[package]] 1715 | name = "windows_x86_64_msvc" 1716 | version = "0.52.6" 1717 | source = "registry+https://github.com/rust-lang/crates.io-index" 1718 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1719 | 1720 | [[package]] 1721 | name = "winnow" 1722 | version = "0.7.13" 1723 | source = "registry+https://github.com/rust-lang/crates.io-index" 1724 | checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" 1725 | dependencies = [ 1726 | "memchr", 1727 | ] 1728 | 1729 | [[package]] 1730 | name = "xtensa-lx" 1731 | version = "0.13.0" 1732 | source = "registry+https://github.com/rust-lang/crates.io-index" 1733 | checksum = "e012d667b0aa6d2592ace8ef145a98bff3e76cca7a644f4181ecd7a916ed289b" 1734 | dependencies = [ 1735 | "critical-section", 1736 | ] 1737 | 1738 | [[package]] 1739 | name = "xtensa-lx-rt" 1740 | version = "0.21.0" 1741 | source = "registry+https://github.com/rust-lang/crates.io-index" 1742 | checksum = "8709f037fb123fe7ff146d2bce86f9dc0dfc53045c016bfd9d703317b6502845" 1743 | dependencies = [ 1744 | "document-features", 1745 | "xtensa-lx", 1746 | "xtensa-lx-rt-proc-macros", 1747 | ] 1748 | 1749 | [[package]] 1750 | name = "xtensa-lx-rt-proc-macros" 1751 | version = "0.5.0" 1752 | source = "registry+https://github.com/rust-lang/crates.io-index" 1753 | checksum = "96fb42cd29c42f8744c74276e9f5bee7b06685bbe5b88df891516d72cb320450" 1754 | dependencies = [ 1755 | "proc-macro2", 1756 | "quote", 1757 | "syn 2.0.101", 1758 | ] 1759 | --------------------------------------------------------------------------------