1#![allow(clippy::missing_safety_doc)]
12
13use core::mem::MaybeUninit;
14#[cfg(feature = "os-irq")]
15use core::sync::atomic::AtomicU8;
16use core::sync::atomic::{AtomicBool, AtomicU32, Ordering};
17
18#[cfg(feature = "nrf9160")]
19use nrf9160_pac as pac;
20
21#[cfg(feature = "nrf9120")]
22use nrf9120_pac as pac;
23
24const IPC_CONF_NUM: usize = 8;
26
27static NOTIFY_ACTIVE: AtomicBool = AtomicBool::new(false);
29
30#[cfg(feature = "os-irq")]
31pub(crate) static OS_IRQ: AtomicU8 = AtomicU8::new(0);
32
33#[derive(Debug, Clone)]
36pub struct NrfxIpcConfig {
37 send_task_config: [u32; IPC_CONF_NUM],
39 receive_event_config: [u32; IPC_CONF_NUM],
41 receive_events_enabled: u32,
43}
44
45type NrfxIpcHandler = extern "C" fn(event_idx: u8, ptr: *mut u8);
48
49#[repr(u32)]
51#[derive(Debug, Copy, Clone)]
52pub enum NrfxErr {
53 Success = 0x0BAD0000,
55 ErrorInternal = (0x0BAD0000 + 1),
57 ErrorNoMem = (0x0BAD0000 + 2),
59 ErrorNotSupported = (0x0BAD0000 + 3),
61 ErrorInvalidParam = (0x0BAD0000 + 4),
63 ErrorInvalidState = (0x0BAD0000 + 5),
65 ErrorInvalidLength = (0x0BAD0000 + 6),
67 ErrorTimeout = (0x0BAD0000 + 7),
69 ErrorForbidden = (0x0BAD0000 + 8),
71 ErrorNull = (0x0BAD0000 + 9),
73 ErrorInvalidAddr = (0x0BAD0000 + 10),
75 ErrorBusy = (0x0BAD0000 + 11),
77 ErrorAlreadyInitialized = (0x0BAD0000 + 12),
79}
80
81static LAST_ERROR: core::sync::atomic::AtomicIsize = core::sync::atomic::AtomicIsize::new(0);
84
85static IPC_CONTEXT: core::sync::atomic::AtomicUsize = core::sync::atomic::AtomicUsize::new(0);
87
88static IPC_HANDLER: core::sync::atomic::AtomicUsize = core::sync::atomic::AtomicUsize::new(0);
90
91#[no_mangle]
93pub extern "C" fn nrf_modem_os_init() {
94 }
96
97#[no_mangle]
99pub extern "C" fn nrf_modem_os_shutdown() {
100 }
102
103#[no_mangle]
105pub extern "C" fn nrf_modem_os_errno_set(errno: isize) {
106 LAST_ERROR.store(errno, core::sync::atomic::Ordering::SeqCst);
107}
108
109pub fn get_last_error() -> isize {
111 LAST_ERROR.load(core::sync::atomic::Ordering::SeqCst)
112}
113
114#[no_mangle]
116pub extern "C" fn nrf_modem_os_busywait(usec: i32) {
117 if usec > 0 {
118 cortex_m::asm::delay((usec as u32) * 64);
120 }
121}
122
123#[no_mangle]
137pub unsafe extern "C" fn nrf_modem_os_timedwait(_context: u32, timeout: *mut i32) -> i32 {
138 if nrf_modem_os_is_in_isr() {
139 return -(nrfxlib_sys::NRF_EPERM as i32);
140 }
141
142 if !nrfxlib_sys::nrf_modem_is_initialized() {
143 return -(nrfxlib_sys::NRF_ESHUTDOWN as i32);
144 }
145
146 if *timeout < -2 {
147 0i32
150 } else {
151 loop {
152 nrf_modem_os_busywait(1000);
153
154 if NOTIFY_ACTIVE.swap(false, Ordering::Relaxed) {
155 return 0;
156 }
157
158 match *timeout {
159 -1 => continue,
160 0 => return -(nrfxlib_sys::NRF_EAGAIN as i32),
161 _ => *timeout -= 1,
162 }
163 }
164 }
165}
166
167#[no_mangle]
171pub extern "C" fn nrf_modem_os_event_notify() {
172 NOTIFY_ACTIVE.store(true, Ordering::SeqCst);
173}
174
175#[no_mangle]
182pub extern "C" fn nrf_modem_os_alloc(num_bytes_requested: usize) -> *mut u8 {
183 unsafe { generic_alloc(num_bytes_requested, &crate::LIBRARY_ALLOCATOR) }
184}
185
186#[no_mangle]
193pub unsafe extern "C" fn nrf_modem_os_free(ptr: *mut u8) {
194 generic_free(ptr, &crate::LIBRARY_ALLOCATOR);
195}
196
197#[no_mangle]
202pub extern "C" fn nrf_modem_os_shm_tx_alloc(num_bytes_requested: usize) -> *mut u8 {
203 unsafe { generic_alloc(num_bytes_requested, &crate::TX_ALLOCATOR) }
204}
205
206#[no_mangle]
210pub unsafe extern "C" fn nrf_modem_os_shm_tx_free(ptr: *mut u8) {
211 generic_free(ptr, &crate::TX_ALLOCATOR);
212}
213
214#[no_mangle]
218pub unsafe extern "C" fn nrfx_ipc_config_load(p_config: *const NrfxIpcConfig) {
219 let config: &NrfxIpcConfig = &*p_config;
220
221 let ipc = &(*pac::IPC_NS::ptr());
222
223 for (i, value) in config.send_task_config.iter().enumerate() {
224 ipc.send_cnf[i].write(|w| w.bits(*value));
225 }
226
227 for (i, value) in config.receive_event_config.iter().enumerate() {
228 ipc.receive_cnf[i].write(|w| w.bits(*value));
229 }
230
231 ipc.intenset
232 .write(|w| w.bits(config.receive_events_enabled));
233}
234
235#[no_mangle]
244pub extern "C" fn nrfx_ipc_init(
245 irq_priority: u8,
246 handler: NrfxIpcHandler,
247 p_context: usize,
248) -> NrfxErr {
249 use cortex_m::interrupt::InterruptNumber;
250 let irq = pac::Interrupt::IPC;
251 let irq_num = usize::from(irq.number());
252 unsafe {
253 cortex_m::peripheral::NVIC::unmask(irq);
254 (*cortex_m::peripheral::NVIC::PTR).ipr[irq_num].write(irq_priority);
255 }
256 IPC_CONTEXT.store(p_context, core::sync::atomic::Ordering::SeqCst);
257 IPC_HANDLER.store(handler as usize, core::sync::atomic::Ordering::SeqCst);
258 NrfxErr::Success
260}
261
262#[no_mangle]
264pub extern "C" fn nrfx_ipc_uninit() {
265 let ipc = unsafe { &(*pac::IPC_NS::ptr()) };
266
267 for i in 0..IPC_CONF_NUM {
268 ipc.send_cnf[i].reset();
269 }
270
271 for i in 0..IPC_CONF_NUM {
272 ipc.receive_cnf[i].reset();
273 }
274
275 ipc.intenset.reset();
276}
277
278#[no_mangle]
279pub extern "C" fn nrfx_ipc_receive_event_enable(event_index: u8) {
280 let ipc = unsafe { &(*pac::IPC_NS::ptr()) };
281 ipc.inten
282 .modify(|r, w| unsafe { w.bits(r.bits() | 1 << event_index) })
283}
284
285#[no_mangle]
286pub extern "C" fn nrfx_ipc_receive_event_disable(event_index: u8) {
287 let ipc = unsafe { &(*pac::IPC_NS::ptr()) };
288 ipc.inten
289 .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << event_index)) })
290}
291
292unsafe fn generic_alloc(num_bytes_requested: usize, heap: &crate::WrappedHeap) -> *mut u8 {
299 let sizeof_usize = core::mem::size_of::<usize>();
300 let mut result = core::ptr::null_mut();
301 critical_section::with(|cs| {
302 let num_bytes_allocated = num_bytes_requested + sizeof_usize;
303 let layout =
304 core::alloc::Layout::from_size_align_unchecked(num_bytes_allocated, sizeof_usize);
305 if let Some(ref mut inner_alloc) = *heap.borrow(cs).borrow_mut() {
306 match inner_alloc.allocate_first_fit(layout) {
307 Ok(real_block) => {
308 let real_ptr = real_block.as_ptr();
309 core::ptr::write_volatile::<usize>(real_ptr as *mut usize, num_bytes_allocated);
311 result = real_ptr.add(sizeof_usize);
313 }
314 Err(_e) => {
315 }
317 }
318 }
319 });
320 result
321}
322
323unsafe fn generic_free(ptr: *mut u8, heap: &crate::WrappedHeap) {
331 let sizeof_usize = core::mem::size_of::<usize>() as isize;
332 critical_section::with(|cs| {
333 let real_ptr = ptr.offset(-sizeof_usize);
335 let num_bytes_allocated = core::ptr::read_volatile::<usize>(real_ptr as *const usize);
336 let layout = core::alloc::Layout::from_size_align_unchecked(
337 num_bytes_allocated,
338 sizeof_usize as usize,
339 );
340 if let Some(ref mut inner_alloc) = *heap.borrow(cs).borrow_mut() {
341 inner_alloc.deallocate(core::ptr::NonNull::new_unchecked(real_ptr), layout);
342 }
343 });
344}
345
346pub unsafe fn nrf_ipc_irq_handler() {
351 let events_map = (*pac::IPC_NS::ptr()).intpend.read().bits();
353
354 let handler_addr = IPC_HANDLER.load(core::sync::atomic::Ordering::SeqCst);
356 let handler = if handler_addr != 0 {
357 let handler = core::mem::transmute::<usize, NrfxIpcHandler>(handler_addr);
358 Some(handler)
359 } else {
360 #[cfg(feature = "defmt")]
361 defmt::warn!("No IPC handler registered");
362 None
363 };
364 let context = IPC_CONTEXT.load(core::sync::atomic::Ordering::SeqCst);
365
366 let mut bitmask = events_map;
368 while bitmask != 0 {
369 let event_idx = bitmask.trailing_zeros();
370 bitmask &= !(1 << event_idx);
371 (*pac::IPC_NS::ptr()).events_receive[event_idx as usize].write(|w| w.bits(0));
372
373 if let Some(handler) = handler {
375 let event_idx = event_idx
376 .try_into()
377 .expect("A u32 has less then 255 trailing zeroes");
378 (handler)(event_idx, context as *mut u8);
379 }
380 }
381}
382
383#[no_mangle]
396pub unsafe extern "C" fn nrf_modem_os_sem_init(
397 sem: *mut *mut core::ffi::c_void,
398 initial_count: core::ffi::c_uint,
399 limit: core::ffi::c_uint,
400) -> core::ffi::c_int {
401 if sem.is_null() || initial_count > limit {
402 return -(nrfxlib_sys::NRF_EINVAL as i32);
403 }
404
405 if (*sem).is_null() {
407 *sem = nrf_modem_os_alloc(core::mem::size_of::<Semaphore>()) as *mut _;
409
410 if (*sem).is_null() {
411 return -(nrfxlib_sys::NRF_ENOMEM as i32);
413 }
414 }
415
416 *((*sem) as *mut Semaphore) = Semaphore {
418 max_value: limit,
419 current_value: AtomicU32::new(initial_count),
420 };
421
422 0
423}
424
425#[no_mangle]
432pub extern "C" fn nrf_modem_os_sem_give(sem: *mut core::ffi::c_void) {
433 unsafe {
434 if sem.is_null() {
435 return;
436 }
437
438 let max_value = (*(sem as *mut Semaphore)).max_value;
439 (*(sem as *mut Semaphore))
440 .current_value
441 .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |val| {
442 (val < max_value).then_some(val + 1)
443 })
444 .ok();
445 }
446}
447
448#[no_mangle]
460pub extern "C" fn nrf_modem_os_sem_take(
461 sem: *mut core::ffi::c_void,
462 mut timeout: core::ffi::c_int,
463) -> core::ffi::c_int {
464 unsafe {
465 if sem.is_null() {
466 return -(nrfxlib_sys::NRF_EAGAIN as i32);
467 }
468
469 if nrfxlib_sys::nrf_modem_os_is_in_isr() {
470 timeout = nrfxlib_sys::NRF_MODEM_OS_NO_WAIT as i32;
471 }
472
473 loop {
474 if (*(sem as *mut Semaphore))
475 .current_value
476 .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |val| {
477 if val > 0 {
478 Some(val - 1)
479 } else {
480 None
481 }
482 })
483 .is_ok()
484 {
485 return 0;
486 }
487
488 match timeout {
489 0 => return -(nrfxlib_sys::NRF_EAGAIN as i32),
490 nrfxlib_sys::NRF_MODEM_OS_FOREVER => {
491 nrf_modem_os_busywait(1000);
492 }
493 _ => {
494 timeout -= 1;
495 nrf_modem_os_busywait(1000);
496 }
497 }
498 }
499 }
500}
501
502#[no_mangle]
510pub extern "C" fn nrf_modem_os_sem_count_get(sem: *mut core::ffi::c_void) -> core::ffi::c_uint {
511 unsafe {
512 if sem.is_null() {
513 return 0;
514 }
515
516 (*(sem as *mut Semaphore))
517 .current_value
518 .load(Ordering::SeqCst)
519 }
520}
521
522struct Semaphore {
523 max_value: u32,
524 current_value: AtomicU32,
525}
526
527#[no_mangle]
529pub extern "C" fn nrf_modem_os_is_in_isr() -> bool {
530 #[cfg(feature = "os-irq")]
531 {
532 let os_irq = OS_IRQ.load(Ordering::Relaxed);
533 match cortex_m::peripheral::SCB::vect_active() {
534 cortex_m::peripheral::scb::VectActive::Interrupt { irqn } => irqn != os_irq,
535 _ => true,
536 }
537 }
538
539 #[cfg(not(feature = "os-irq"))]
540 {
541 cortex_m::peripheral::SCB::vect_active()
542 != cortex_m::peripheral::scb::VectActive::ThreadMode
543 }
544}
545
546struct MutexLock {
548 lock: AtomicBool,
549}
550
551impl MutexLock {
552 pub fn lock(&self) -> bool {
553 matches!(
554 self.lock
555 .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst),
556 Ok(false)
557 )
558 }
559
560 pub fn unlock(&self) {
561 self.lock.store(false, Ordering::SeqCst);
562 }
563}
564
565#[no_mangle]
577pub unsafe extern "C" fn nrf_modem_os_mutex_init(
578 mutex: *mut *mut core::ffi::c_void,
579) -> core::ffi::c_int {
580 if mutex.is_null() {
581 return -(nrfxlib_sys::NRF_EINVAL as i32);
582 }
583
584 if (*mutex).is_null() {
586 let p = nrf_modem_os_alloc(core::mem::size_of::<MaybeUninit<MutexLock>>())
588 as *mut MaybeUninit<MutexLock>;
589
590 if p.is_null() {
591 return -(nrfxlib_sys::NRF_ENOMEM as i32);
593 }
594
595 p.write(MaybeUninit::new(MutexLock {
597 lock: AtomicBool::new(false),
598 }));
599
600 *mutex = p as *mut core::ffi::c_void;
602 } else {
603 (*(mutex as *mut MutexLock)).unlock();
605 }
606
607 0
608}
609
610#[no_mangle]
620pub unsafe extern "C" fn nrf_modem_os_mutex_lock(
621 mutex: *mut core::ffi::c_void,
622 timeout: core::ffi::c_int,
623) -> core::ffi::c_int {
624 if mutex.is_null() {
625 return -(nrfxlib_sys::NRF_EINVAL as i32);
626 }
627
628 let mutex = &*(mutex as *mut MutexLock);
629
630 let mut locked = mutex.lock();
631
632 if locked || timeout == nrfxlib_sys::NRF_MODEM_OS_NO_WAIT as i32 {
633 return if locked {
634 0
635 } else {
636 -(nrfxlib_sys::NRF_EAGAIN as i32)
637 };
638 }
639
640 let mut elapsed = 0;
641 const WAIT_US: core::ffi::c_int = 100;
642
643 while !locked {
644 nrf_modem_os_busywait(WAIT_US);
645
646 if timeout != nrfxlib_sys::NRF_MODEM_OS_FOREVER {
647 elapsed += WAIT_US;
648 if (elapsed / 1000) > timeout {
649 return -(nrfxlib_sys::NRF_EAGAIN as i32);
650 }
651 }
652
653 locked = mutex.lock();
654 }
655
656 0
657}
658
659#[no_mangle]
669pub unsafe extern "C" fn nrf_modem_os_mutex_unlock(
670 mutex: *mut core::ffi::c_void,
671) -> core::ffi::c_int {
672 if mutex.is_null() {
673 return -(nrfxlib_sys::NRF_EINVAL as i32);
674 }
675 (*(mutex as *mut MutexLock)).unlock();
676 0
677}
678
679#[no_mangle]
686pub unsafe extern "C" fn nrf_modem_os_log_wrapped(
687 _level: core::ffi::c_int,
688 _msg: *const core::ffi::c_char,
689) {
690 #[cfg(all(feature = "defmt", feature = "modem-log"))]
691 {
692 let msg = core::ffi::CStr::from_ptr(_msg);
693 if let Ok(msg) = msg.to_str() {
694 defmt::trace!("Modem log <{}>: {}", _level, msg);
695 }
696 }
697}
698
699#[no_mangle]
707pub extern "C" fn nrf_modem_os_logdump(
708 _level: core::ffi::c_int,
709 _strdata: *const core::ffi::c_char,
710 _data: *const core::ffi::c_void,
711 _len: core::ffi::c_int,
712) {
713 }