esp_rom_sys/
lib.rs

1#![doc = include_str!("../README.md")]
2//! ## Feature Flags
3#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
4#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")]
5#![allow(rustdoc::bare_urls)]
6#![no_std]
7
8use core::ffi::c_char;
9
10pub(crate) mod reg_access;
11
12#[cfg(feature = "__internal_rom_symbols")]
13pub mod generated_rom_symbols;
14
15#[doc(hidden)]
16/// Helper macro for checking doctest code snippets
17#[macro_export]
18macro_rules! before_snippet {
19    () => {
20        r#"
21# #![no_std]
22# use procmacros::handler;
23# use esp_hal::{interrupt::{self, InterruptConfigurable}, time::{Duration, Instant, Rate}};
24# macro_rules! println {
25#     ($($tt:tt)*) => { };
26# }
27# macro_rules! print {
28#     ($($tt:tt)*) => { };
29# }
30# #[panic_handler]
31# fn panic(_ : &core::panic::PanicInfo) -> ! {
32#     loop {}
33# }
34# fn main() {
35#   let _ = example();
36# }
37# struct ExampleError {}
38# impl <T> From<T> for ExampleError where T: core::fmt::Debug {
39#   fn from(_value: T) -> Self {
40#       Self{}
41#   }
42# }
43# async fn example() -> Result<(), ExampleError> {
44#   let mut peripherals = esp_hal::init(esp_hal::Config::default());
45"#
46    };
47}
48
49pub mod rom;
50mod syscall;
51
52pub use syscall::{_reent, SYSCALL_TABLE, init_syscall_table};
53
54/// This is needed by `libesp_rom.a` (if used)
55/// Other crates (i.e. esp-radio) also rely on this being defined somewhere
56#[unsafe(no_mangle)]
57unsafe extern "C" fn __assert_func(
58    file: *const core::ffi::c_char,
59    line: i32,
60    func: *const core::ffi::c_char,
61    expr: *const core::ffi::c_char,
62) -> ! {
63    unsafe {
64        panic!(
65            "__assert_func in {}:{} ({}): {}",
66            core::ffi::CStr::from_ptr(file).to_str().unwrap(),
67            line,
68            core::ffi::CStr::from_ptr(func).to_str().unwrap(),
69            core::ffi::CStr::from_ptr(expr).to_str().unwrap(),
70        );
71    }
72}
73
74// We cannot just use the ROM function since (on some targets, currently ESP32-S2) it calls
75// `__getreent`
76//
77// From docs: The __getreent() function returns a per-task pointer to struct
78// _reent in newlib libc. This structure is allocated on the TCB of each task.
79// i.e. it assumes a FreeRTOS task calling it.
80#[unsafe(no_mangle)]
81unsafe extern "C" fn __strcasecmp(
82    s1: *const core::ffi::c_char,
83    s2: *const core::ffi::c_char,
84) -> i32 {
85    let mut i = 0;
86    loop {
87        unsafe {
88            let s1_i = s1.add(i);
89            let s2_i = s2.add(i);
90
91            #[allow(clippy::unnecessary_cast)]
92            let val = (*s1_i as u8).to_ascii_lowercase() as i32
93                - (*s2_i as u8).to_ascii_lowercase() as i32;
94            if val != 0 || *s1_i == 0 {
95                return val;
96            }
97        }
98
99        i += 1;
100    }
101}
102
103#[unsafe(no_mangle)]
104unsafe extern "C" fn __strnlen(chars: *const c_char, maxlen: isize) -> usize {
105    let mut len = 0;
106    loop {
107        unsafe {
108            if chars.offset(len).read_volatile() == 0 {
109                break;
110            }
111            len += 1;
112
113            if len >= maxlen {
114                break;
115            }
116        }
117    }
118
119    len as usize
120}
121
122// We cannot just use the ROM function since it calls `__getreent`
123//
124// From docs: The __getreent() function returns a per-task pointer to struct
125// _reent in newlib libc. This structure is allocated on the TCB of each task.
126// i.e. it assumes a FreeRTOS task calling it.
127#[unsafe(no_mangle)]
128unsafe extern "C" fn __atoi(str: *const i8) -> i32 {
129    let mut sign: i32 = 1;
130    let mut res: i32 = 0;
131    let mut idx = 0;
132
133    // skip leading spaces
134    while unsafe { str.add(idx).read() } as u8 == b' ' {
135        idx += 1;
136    }
137
138    // check sign
139    let c = unsafe { str.add(idx).read() } as u8;
140    if c == b'-' || c == b'+' {
141        if c == b'-' {
142            sign = -1;
143        }
144        idx += 1;
145    }
146
147    // parse number digit by digit
148    loop {
149        let c = unsafe { str.add(idx).read() } as u8;
150
151        if !c.is_ascii_digit() {
152            break;
153        }
154
155        // if the result would exceed the bounds - return max-value
156        if res > i32::MAX / 10 || (res == i32::MAX / 10 && c - b'0' > 7) {
157            return if sign == 1 { i32::MAX } else { i32::MIN };
158        }
159
160        res = 10 * res + (c - b'0') as i32;
161        idx += 1;
162    }
163    res * sign
164}
165
166#[derive(Debug, Copy, Clone)]
167#[repr(C)]
168struct Tm {
169    tm_sec: u32,   // seconds after the minute - [0, 60] including leap second
170    tm_min: u32,   // minutes after the hour - [0, 59]
171    tm_hour: u32,  // hours since midnight - [0, 23]
172    tm_mday: u32,  // day of the month - [1, 31]
173    tm_mon: u32,   // months since January - [0, 11]
174    tm_year: u32,  // years since 1900
175    tm_wday: u32,  // days since Sunday - [0, 6]
176    tm_yday: u32,  // days since January 1 - [0, 365]
177    tm_isdst: u32, // daylight savings time flag
178}
179
180#[unsafe(no_mangle)]
181unsafe extern "C" fn __mktime(time: *const Tm) -> i64 {
182    let time = unsafe { *time };
183
184    // Simplified implementation, ignoring time zones, leap seconds, and other
185    // complexities
186    let mut days_in_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
187
188    let is_leap_year = |year: u32| {
189        year.is_multiple_of(4) && (!year.is_multiple_of(100) || year.is_multiple_of(400))
190    };
191
192    let mut days = 0;
193    let year = time.tm_year + 1900;
194    for y in 1970..year {
195        days += if is_leap_year(y) { 366 } else { 365 };
196    }
197
198    if is_leap_year(year) {
199        days_in_month[1] = 29;
200    }
201
202    for m in 0..time.tm_mon {
203        days += days_in_month[m as usize];
204    }
205    days += time.tm_mday - 1;
206
207    let seconds = days * 24 * 60 * 60 + time.tm_hour * 60 * 60 + time.tm_min * 60 + time.tm_sec;
208
209    seconds as i64
210}