This repository has been archived on 2026-08-31. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
donglora/vendor/fixed/src/log10.rs
T
swaitsandClaude Opus 4.6 3102fc747a feat: add display UI with splash screen, dashboard, and RSSI sparkline
Implement full SSD1306 OLED display support:
- Splash screen on boot (1.5s) with project name, version, board
- Dashboard showing radio state, config, counters, RSSI/SNR
- RSSI history sparkline (64-sample ring buffer, 2px-wide bars)
- DisplayOn/DisplayOff host commands routed via dedicated channel
- Pure render functions against generic DrawTarget (no hardware coupling)
- Display on/off control bypasses radio task entirely

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 20:42:54 -06:00

326 lines
10 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Copyright © 2018–2025 Trevor Spiteri
// This library is free software: you can redistribute it and/or
// modify it under the terms of either
//
// * the Apache License, Version 2.0 or
// * the MIT License
//
// at your option.
//
// You should have recieved copies of the Apache License and the MIT
// License along with the library. If not, see
// <https://www.apache.org/licenses/LICENSE-2.0> and
// <https://opensource.org/licenses/MIT>.
// the value must be positive for all public functions
pub mod frac_part {
use core::num::NonZero;
// MAX / 1000 (0) < val <= MAX (255)
// -3 <= log <= -1
#[inline]
pub const fn u8(val: NonZero<u8>) -> i32 {
let val = val.get();
if val > 25 {
-1
} else if val > 2 {
-2
} else {
-3
}
}
// MAX / 100_000 (0) < val <= MAX (65_535)
// -5 <= log <= -1
#[inline]
pub const fn u16(val: NonZero<u16>) -> i32 {
let val = val.get();
if val > 6553 {
-1
} else if val > 655 {
-2
} else if val > 65 {
-3
} else if val > 6 {
-4
} else {
-5
}
}
// 0 < val <= MAX
// -10 <= log <= -1
pub const fn u32(val: NonZero<u32>) -> i32 {
const MAX: u32 = u32::MAX;
let mut val = val.get();
if val <= MAX / 100_000_000 {
val *= 100_000_000;
// At this point, we have shifted out 8 digits, and we can only shift out 2 more.
// We can only check up to -2 more because -10 <= log <= -8.
if val > MAX / 10 {
-9
} else {
debug_assert!(val > MAX / 100);
-10
}
} else {
greater_equal_m8_u32(val)
}
}
// 0 < val <= MAX
// -20 <= log <= -1
pub const fn u64(val: NonZero<u64>) -> i32 {
const MAX: u64 = u64::MAX;
let mut val = val.get();
let mut log = 0;
if val <= MAX / 10_000_000_000_000_000 {
// After this, we can only check up to -4 more because -20 <= log <= -16.
// That is, we can skip the checks against MAX / 100_000_000 and MAX / 10_000.
val *= 10_000_000_000_000_000;
log += -16;
} else {
if val <= MAX / 100_000_000 {
val *= 100_000_000;
log += -8;
}
if val <= MAX / 10_000 {
val *= 10_000;
log += -4;
}
}
log + if val > MAX / 10 {
-1
} else if val > MAX / 100 {
-2
} else if val > MAX / 1000 {
-3
} else {
debug_assert!(val > MAX / 10_000);
-4
}
}
// 0 < val <= MAX
// -39 <= log <= -1
pub const fn u128(val: NonZero<u128>) -> i32 {
const MAX: u128 = u128::MAX;
let mut val = val.get();
let mut log = 0;
if val <= MAX / 100_000_000_000_000_000_000_000_000_000_000 {
val *= 100_000_000_000_000_000_000_000_000_000_000;
// At this point we have shifted out 32 digits, and we can only shift out 7 more.
// We can
// * use val >> 96 because we have shifted out 32 decimal digits (106 bits)
// * only check up to -8 more because -39 <= log <= -32
return -32 + greater_equal_m8_u32((val >> 96) as u32);
}
if val <= MAX / 10_000_000_000_000_000 {
val *= 10_000_000_000_000_000;
log += -16;
}
if val <= MAX / 100_000_000 {
val *= 100_000_000;
log += -8;
}
if log == -24 {
// At this point we have shifted out 24 digits, and we can only shift out 15 more.
// We can
// * use val >> 64 because we have shifted out 24 decimal digits (79 bits)
// * only check up to -8 more because -32 <= log <= -24
return -24 + greater_equal_m8_u64((val >> 64) as u64);
}
// We have *not* shifted out enough decimal digits, so we must *not* convert to u32 or u64.
if val <= MAX / 10_000 {
val *= 10_000;
log += -4;
}
log + if val > MAX / 10 {
-1
} else if val > MAX / 100 {
-2
} else if val > MAX / 1000 {
-3
} else {
debug_assert!(val > MAX / 10_000);
-4
}
}
// MAX / 100_000_000 < val <= MAX
// -8 <= log <= -1
const fn greater_equal_m8_u32(mut val: u32) -> i32 {
const MAX: u32 = u32::MAX;
debug_assert!(val > MAX / 100_000_000);
let mut log = 0;
if val <= MAX / 10_000 {
val *= 10_000;
log += -4;
}
log + if val > MAX / 10 {
-1
} else if val > MAX / 100 {
-2
} else if val > MAX / 1000 {
-3
} else {
debug_assert!(val > MAX / 10_000);
-4
}
}
// MAX / 100_000_000 < val <= MAX
// -8 <= log <= 1
const fn greater_equal_m8_u64(mut val: u64) -> i32 {
const MAX: u64 = u64::MAX;
debug_assert!(val > MAX / 100_000_000);
let mut log = 0;
if val <= MAX / 10_000 {
val *= 10_000;
log += -4;
}
log + if val > MAX / 10 {
-1
} else if val > MAX / 100 {
-2
} else if val > MAX / 1000 {
-3
} else {
debug_assert!(val > MAX / 10_000);
-4
}
}
}
// check log10() and log(10) in tandem
#[cfg(test)]
mod tests {
use crate::log;
use crate::log::Base;
use crate::log10;
use core::num::NonZero;
const DEC: Base = match Base::new(10) {
Some(s) => s,
None => unreachable!(),
};
macro_rules! check_loop {
($T:ident) => {
for i in 0..=$T::MAX.ilog10() as i32 {
let p = (10 as $T).pow(i as u32);
let nz = NonZero::<$T>::new(p).unwrap();
if i > 0 {
let nz_m1 = NonZero::<$T>::new(p - 1).unwrap();
assert_eq!((p - 1).ilog10() as i32, i - 1);
assert_eq!(log::int_part::$T(nz_m1, DEC), i - 1);
}
assert_eq!(p.ilog10() as i32, i);
assert_eq!(log::int_part::$T(nz, DEC), i);
let nz_p1 = NonZero::<$T>::new(p + 1).unwrap();
assert_eq!((p + 1).ilog10() as i32, i);
assert_eq!(log::int_part::$T(nz_p1, DEC), i);
}
for i in 0..-log10::frac_part::$T(NonZero::<$T>::new(1).unwrap()) {
let p = <$T>::MAX / (10 as $T).pow(i as u32);
let nz = NonZero::<$T>::new(p).unwrap();
if p > 1 {
let nz_m1 = NonZero::<$T>::new(p - 1).unwrap();
assert_eq!(log10::frac_part::$T(nz_m1), -1 - i);
assert_eq!(log::frac_part::$T(nz_m1, DEC), -1 - i);
}
assert_eq!(log10::frac_part::$T(nz), -1 - i);
assert_eq!(log::frac_part::$T(nz, DEC), -1 - i);
if i > 0 {
let nz_p1 = NonZero::<$T>::new(p + 1).unwrap();
assert_eq!(log10::frac_part::$T(nz_p1), -i);
assert_eq!(log::frac_part::$T(nz_p1, DEC), -i);
}
}
};
}
#[test]
fn log10_u8() {
let one = NonZero::<u8>::new(1).unwrap();
assert_eq!(1u8.ilog10(), 0);
assert_eq!(log::int_part::u8(one, DEC), 0);
assert_eq!(u8::MAX.ilog10(), 2);
assert_eq!(log::int_part::u8(NonZero::<u8>::MAX, DEC), 2);
assert_eq!(log10::frac_part::u8(one), -3);
assert_eq!(log::frac_part::u8(one, DEC), -3);
assert_eq!(log10::frac_part::u8(NonZero::<u8>::MAX), -1);
assert_eq!(log::frac_part::u8(NonZero::<u8>::MAX, DEC), -1);
check_loop! { u8 }
}
#[test]
fn log10_u16() {
let one = NonZero::<u16>::new(1).unwrap();
assert_eq!(1u16.ilog10(), 0);
assert_eq!(log::int_part::u16(one, DEC), 0);
assert_eq!(u16::MAX.ilog10(), 4);
assert_eq!(log::int_part::u16(NonZero::<u16>::MAX, DEC), 4);
assert_eq!(log10::frac_part::u16(one), -5);
assert_eq!(log::frac_part::u16(one, DEC), -5);
assert_eq!(log10::frac_part::u16(NonZero::<u16>::MAX), -1);
assert_eq!(log::frac_part::u16(NonZero::<u16>::MAX, DEC), -1);
check_loop! { u16 }
}
#[test]
fn log10_u32() {
let one = NonZero::<u32>::new(1).unwrap();
assert_eq!(1u32.ilog10(), 0);
assert_eq!(log::int_part::u32(NonZero::<u32>::new(1).unwrap(), DEC), 0);
assert_eq!(u32::MAX.ilog10(), 9);
assert_eq!(log::int_part::u32(NonZero::<u32>::MAX, DEC), 9);
assert_eq!(log10::frac_part::u32(one), -10);
assert_eq!(log::frac_part::u32(one, DEC), -10);
assert_eq!(log10::frac_part::u32(NonZero::<u32>::MAX), -1);
assert_eq!(log::frac_part::u32(NonZero::<u32>::MAX, DEC), -1);
check_loop! { u32 }
}
#[test]
fn log10_u64() {
let one = NonZero::<u64>::new(1).unwrap();
assert_eq!(1u64.ilog10(), 0);
assert_eq!(log::int_part::u64(one, DEC), 0);
assert_eq!(u64::MAX.ilog10(), 19);
assert_eq!(log::int_part::u64(NonZero::<u64>::MAX, DEC), 19);
assert_eq!(log10::frac_part::u64(one), -20);
assert_eq!(log::frac_part::u64(one, DEC), -20);
assert_eq!(log10::frac_part::u64(NonZero::<u64>::MAX), -1);
assert_eq!(log::frac_part::u64(NonZero::<u64>::MAX, DEC), -1);
check_loop! { u64 }
}
#[test]
fn log10_u128() {
let one = NonZero::<u128>::new(1).unwrap();
assert_eq!(1u128.ilog10(), 0);
assert_eq!(log::int_part::u128(one, DEC), 0);
assert_eq!(u128::MAX.ilog10(), 38);
assert_eq!(log::int_part::u128(NonZero::<u128>::MAX, DEC), 38);
assert_eq!(log10::frac_part::u128(one), -39);
assert_eq!(log::frac_part::u128(one, DEC), -39);
assert_eq!(log10::frac_part::u128(NonZero::<u128>::MAX), -1);
assert_eq!(log::frac_part::u128(NonZero::<u128>::MAX, DEC), -1);
check_loop! { u128 }
}
}