From 0988ecd8a885b92281b64f367a9ba00f67f5d3c4 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Thu, 18 Jul 2024 10:26:50 +0200 Subject: [PATCH 1/2] Add CI job for avr target --- .github/workflows/ci.yml | 50 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 10d06da5..92fce557 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -62,3 +62,53 @@ jobs: - name: Check documentation if: matrix.target == 'x86_64-unknown-linux-gnu' run: RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --workspace + + build-avr: + runs-on: ubuntu-latest + + steps: + - name: Install build dependencies + shell: bash + run: | + env && pwd && sudo apt-get update -y -qq && sudo apt-get install -y -qq llvm gcc-avr avr-libc libclang-dev + + - name: Install rust + run: rustup toolchain install --profile minimal --component=rust-src nightly + + - uses: actions/checkout@v3 + + - name: Configure target + run: | + cat < avr-atmega328p.json + { + "arch": "avr", + "atomic-cas": false, + "cpu": "atmega328p", + "data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8", + "eh-frame-header": false, + "exe-suffix": ".elf", + "late-link-args": { + "gcc": [ + "-lgcc" + ] + }, + "linker": "avr-gcc", + "llvm-target": "avr-unknown-unknown", + "max-atomic-width": 8, + "no-default-libraries": false, + "pre-link-args": { + "gcc": [ + "-mmcu=atmega328p" + ] + }, + "relocation-model": "static", + "target-c-int-width": "16", + "target-pointer-width": "16" + } + EOT + + - name: Patch delog + run: echo 'delog = { version = "0.1.6", git = "https://github.com/LechevSpace/delog.git", rev = "e83f3fd" }' >> Cargo.toml + + - name: Build avr + run: cargo +nightly build -Z build-std=core --target=./avr-atmega328p.json --workspace --release From 7614f8e18b0b0d11f4ba6fa652bc73f2e4c8bd92 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Thu, 18 Jul 2024 11:10:30 +0200 Subject: [PATCH 2/2] Handle platforms where c_int is not i32 Some functions assume that c_int is always i32. This is not true for all platforms. This patch adapts those functions to handle those cases. Some littlefs functions return an error code (c_int) from functions returning i32. In these cases, error codes are truncated to c_int::MIN. --- CHANGELOG.md | 1 + src/fs.rs | 44 +++++++++++++++++++++++++++----------------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e46a3163..0ca580db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Added `Filesystem::mount_or_else` function ([#57][]) - Marked `Path::is_empty`, `Path::from_bytes_with_nul`, `Path::from_cstr`, `Path::from_cstr_unchecked`, `Path::as_str_ref_with_trailing_nul`, `Path::as_str`, and `PathBuf::new` as `const`. - Made `fs::FileOpenFlags` public and added `From` for `fs::OpenOptions`. +- Support platforms where `c_int` is not `i32`. ### Fixed diff --git a/src/fs.rs b/src/fs.rs index 5be952d3..e8a42e91 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -35,6 +35,13 @@ fn result_from(return_value: T, error_code: ll::lfs_error) -> Result { } } +pub fn u32_result(return_value: i32) -> Result { + u32::try_from(return_value).map_err(|_| { + let error_code = c_int::try_from(return_value).unwrap_or(c_int::MIN); + Error::new(error_code).unwrap() + }) +} + struct Cache { read: UnsafeCell>, write: UnsafeCell>, @@ -246,7 +253,9 @@ impl Filesystem<'_, Storage> { /// by this method available, at any given time. pub fn available_blocks(&self) -> Result { let return_code = unsafe { ll::lfs_fs_size(&mut self.alloc.borrow_mut().state) }; - result_from(return_code, return_code).map(|blocks| self.total_blocks() - blocks as usize) + u32_result(return_code) + .map(|blocks| usize::try_from(blocks).unwrap_or(usize::MAX)) + .map(|blocks| self.total_blocks().saturating_sub(blocks)) } /// Available number of unused bytes in the filesystem @@ -430,17 +439,18 @@ impl Filesystem<'_, Storage> { ) }; - if return_code >= 0 { - let total_size = usize::try_from(return_code).unwrap_or(usize::MAX); - return Ok(Some(Attribute::new(buffer, total_size))); - } - if return_code == ll::lfs_error_LFS_ERR_NOATTR { - return Ok(None); - } - - result_from((), return_code)?; - // TODO: get rid of this - unreachable!(); + u32_result(return_code) + .map(|n| { + let total_size = usize::try_from(n).unwrap_or(usize::MAX); + Some(Attribute::new(buffer, total_size)) + }) + .or_else(|err| { + if err == Error::NO_ATTRIBUTE { + Ok(None) + } else { + Err(err) + } + }) } /// Remove attribute. @@ -516,7 +526,7 @@ impl Filesystem<'_, Storage> { /// C callback interface used by LittleFS to sync data with the lower level interface below the /// filesystem. Note that this function currently does nothing. - extern "C" fn lfs_config_sync(_c: *const ll::lfs_config) -> i32 { + extern "C" fn lfs_config_sync(_c: *const ll::lfs_config) -> c_int { // println!("in lfs_config_sync"); // Do nothing; we presume that data is synchronized. 0 @@ -653,7 +663,7 @@ impl<'a, 'b, Storage: driver::Storage> File<'a, 'b, Storage> { addr_of_mut!((*(*self.alloc.borrow_mut())).state), ) }; - result_from(return_code as usize, return_code) + u32_result(return_code).map(|n| n as usize) } pub fn is_empty(&self) -> Result { @@ -860,7 +870,7 @@ impl io::Read for File<'_, '_, S> { buf.len() as u32, ) }; - result_from(return_code as usize, return_code) + u32_result(return_code).map(|n| n as usize) } } @@ -877,7 +887,7 @@ impl io::Seek for File<'_, '_, S> { pos.whence(), ) }; - result_from(return_code as usize, return_code) + u32_result(return_code).map(|n| n as usize) } } @@ -894,7 +904,7 @@ impl io::Write for File<'_, '_, S> { buf.len() as u32, ) }; - result_from(return_code as usize, return_code) + u32_result(return_code).map(|n| n as usize) } fn flush(&self) -> Result<()> {