88//! Dual-licensed under MIT and Apache 2.0. See the [README](../README.md) for
99//! more details.
1010
11- /// Stores the last error from the library. See `bsd_os_errno_set` and
11+ use log:: debug;
12+
13+ /// Number of IPC configurations in `NrfxIpcConfig`
14+ const IPC_CONF_NUM : usize = 8 ;
15+
16+ /// Used by `libmodem` to configure the IPC peripheral. See `nrfx_ipc_config_t`
17+ /// in `nrfx/drivers/include/nrfx_ipc.h`.
18+ #[ derive( Debug , Clone ) ]
19+ pub struct NrfxIpcConfig {
20+ /// Configuration of the connection between signals and IPC channels.
21+ send_task_config : [ u32 ; IPC_CONF_NUM ] ,
22+ /// Configuration of the connection between events and IPC channels.
23+ receive_event_config : [ u32 ; IPC_CONF_NUM ] ,
24+ /// Bitmask with events to be enabled to generate interrupt.
25+ receive_events_enabled : u32 ,
26+ }
27+
28+ /// IPC callback function type
29+ type NrfxIpcHandler = extern "C" fn ( event_mask : u32 , ptr : * mut u8 ) ;
30+
31+ /// IPC error type
32+ #[ repr( u32 ) ]
33+ #[ derive( Debug , Copy , Clone ) ]
34+ pub enum NrfxErr {
35+ ///< Operation performed successfully.
36+ Success = 0x0BAD0000 ,
37+ ///< Internal error.
38+ ErrorInternal = ( 0x0BAD0000 + 1 ) ,
39+ ///< No memory for operation.
40+ ErrorNoMem = ( 0x0BAD0000 + 2 ) ,
41+ ///< Not supported.
42+ ErrorNotSupported = ( 0x0BAD0000 + 3 ) ,
43+ ///< Invalid parameter.
44+ ErrorInvalidParam = ( 0x0BAD0000 + 4 ) ,
45+ ///< Invalid state, operation disallowed in this state.
46+ ErrorInvalidState = ( 0x0BAD0000 + 5 ) ,
47+ ///< Invalid length.
48+ ErrorInvalidLength = ( 0x0BAD0000 + 6 ) ,
49+ ///< Operation timed out.
50+ ErrorTimeout = ( 0x0BAD0000 + 7 ) ,
51+ ///< Operation is forbidden.
52+ ErrorForbidden = ( 0x0BAD0000 + 8 ) ,
53+ ///< Null pointer.
54+ ErrorNull = ( 0x0BAD0000 + 9 ) ,
55+ ///< Bad memory address.
56+ ErrorInvalidAddr = ( 0x0BAD0000 + 10 ) ,
57+ ///< Busy.
58+ ErrorBusy = ( 0x0BAD0000 + 11 ) ,
59+ ///< Module already initialized.
60+ ErrorAlreadyInitialized = ( 0x0BAD0000 + 12 ) ,
61+ }
62+
63+ /// Stores the last error from the library. See `nrf_modem_os_errno_set` and
1264/// `get_last_error`.
1365static LAST_ERROR : core:: sync:: atomic:: AtomicI32 = core:: sync:: atomic:: AtomicI32 :: new ( 0 ) ;
1466
15- extern "C" {
16- // This function is in the C library but not in the headers generated by
17- // nrfxlib-sys.
18- pub fn IPC_IRQHandler ( ) ;
19- }
67+ /// Remembers the IPC interrupt context we were given
68+ static IPC_CONTEXT : core :: sync :: atomic :: AtomicUsize = core :: sync :: atomic :: AtomicUsize :: new ( 0 ) ;
69+
70+ /// Remembers the IPC handler function we were given
71+ static IPC_HANDLER : core :: sync :: atomic :: AtomicUsize = core :: sync :: atomic :: AtomicUsize :: new ( 0 ) ;
2072
2173/// Function required by BSD library. We need to set the EGU1 interrupt.
2274#[ no_mangle]
23- pub extern "C" fn bsd_os_application_irq_set ( ) {
75+ pub extern "C" fn nrf_modem_os_application_irq_set ( ) {
2476 cortex_m:: peripheral:: NVIC :: pend ( crate :: cpu:: Interrupt :: EGU1 ) ;
2577}
2678
2779/// Function required by BSD library. We need to clear the EGU1 interrupt.
2880#[ no_mangle]
29- pub extern "C" fn bsd_os_application_irq_clear ( ) {
81+ pub extern "C" fn nrf_modem_os_application_irq_clear ( ) {
3082 cortex_m:: peripheral:: NVIC :: unpend ( crate :: cpu:: Interrupt :: EGU1 ) ;
3183}
3284
3385/// Function required by BSD library. We need to set the EGU2 interrupt.
3486#[ no_mangle]
35- pub extern "C" fn bsd_os_trace_irq_set ( ) {
87+ pub extern "C" fn nrf_modem_os_trace_irq_set ( ) {
3688 cortex_m:: peripheral:: NVIC :: pend ( crate :: cpu:: Interrupt :: EGU2 ) ;
3789}
3890
3991/// Function required by BSD library. We need to clear the EGU2 interrupt.
4092#[ no_mangle]
41- pub extern "C" fn bsd_os_trace_irq_clear ( ) {
93+ pub extern "C" fn nrf_modem_os_trace_irq_clear ( ) {
4294 cortex_m:: peripheral:: NVIC :: unpend ( crate :: cpu:: Interrupt :: EGU2 ) ;
4395}
4496
4597/// Function required by BSD library. We have no init to do.
4698#[ no_mangle]
47- pub extern "C" fn bsd_os_init ( ) {
99+ pub extern "C" fn nrf_modem_os_init ( ) {
48100 // Nothing
49101}
50102
51103/// Function required by BSD library. Stores an error code we can read later.
52104#[ no_mangle]
53- pub extern "C" fn bsd_os_errno_set ( errno : i32 ) {
105+ pub extern "C" fn nrf_modem_os_errno_set ( errno : i32 ) {
54106 LAST_ERROR . store ( errno, core:: sync:: atomic:: Ordering :: SeqCst ) ;
55107}
56108
@@ -61,7 +113,7 @@ pub fn get_last_error() -> i32 {
61113
62114/// Function required by BSD library
63115#[ no_mangle]
64- pub extern "C" fn bsd_os_timedwait ( _context : u32 , p_timeout_ms : * const i32 ) -> i32 {
116+ pub extern "C" fn nrf_modem_os_timedwait ( _context : u32 , p_timeout_ms : * const i32 ) -> i32 {
65117 let timeout_ms = unsafe { * p_timeout_ms } ;
66118 if timeout_ms < 0 {
67119 // With Zephyr, negative timeouts pend on a semaphore with K_FOREVER.
@@ -76,13 +128,189 @@ pub extern "C" fn bsd_os_timedwait(_context: u32, p_timeout_ms: *const i32) -> i
76128
77129/// Function required by BSD library
78130#[ no_mangle]
79- pub extern "C" fn bsd_os_trace_put ( _data : * const u8 , _len : u32 ) -> i32 {
131+ pub extern "C" fn nrf_modem_os_trace_put ( _data : * const u8 , _len : u32 ) -> i32 {
80132 // Do nothing
81133 0
82134}
83135
84136/// Function required by BSD library
85137#[ no_mangle]
86- pub extern "C" fn bsd_irrecoverable_error_handler ( err : u32 ) -> ! {
138+ pub extern "C" fn nrf_modem_irrecoverable_error_handler ( err : u32 ) -> ! {
87139 panic ! ( "bsd_irrecoverable_error_handler({})" , err) ;
88140}
141+
142+ /// The Modem library needs to dynamically allocate memory (a heap) for proper
143+ /// functioning. This memory is used to store the internal data structures that
144+ /// are used to manage the communication between the application core and the
145+ /// modem core. This memory is never shared with the modem core and hence, it
146+ /// can be located anywhere in the application core's RAM instead of the shared
147+ /// memory regions. This function allocates dynamic memory for the library.
148+ #[ no_mangle]
149+ pub extern "C" fn nrf_modem_os_alloc ( num_bytes_requested : usize ) -> * mut u8 {
150+ unsafe { generic_alloc ( num_bytes_requested, & crate :: LIBRARY_ALLOCATOR ) }
151+ }
152+
153+ /// The Modem library needs to dynamically allocate memory (a heap) for proper
154+ /// functioning. This memory is used to store the internal data structures that
155+ /// are used to manage the communication between the application core and the
156+ /// modem core. This memory is never shared with the modem core and hence, it
157+ /// can be located anywhere in the application core's RAM instead of the shared
158+ /// memory regions. This function allocates dynamic memory for the library.
159+ #[ no_mangle]
160+ pub extern "C" fn nrf_modem_os_free ( ptr : * mut u8 ) {
161+ unsafe {
162+ generic_free ( ptr, & crate :: LIBRARY_ALLOCATOR ) ;
163+ }
164+ }
165+
166+ /// Allocate a buffer on the TX area of shared memory.
167+ ///
168+ /// @param bytes Buffer size.
169+ /// @return pointer to allocated memory
170+ #[ no_mangle]
171+ pub extern "C" fn nrf_modem_os_shm_tx_alloc ( num_bytes_requested : usize ) -> * mut u8 {
172+ unsafe { generic_alloc ( num_bytes_requested, & crate :: TX_ALLOCATOR ) }
173+ }
174+
175+ /// Free a shared memory buffer in the TX area.
176+ ///
177+ /// @param ptr Th buffer to free.
178+ #[ no_mangle]
179+ pub extern "C" fn nrf_modem_os_shm_tx_free ( ptr : * mut u8 ) {
180+ unsafe {
181+ generic_free ( ptr, & crate :: TX_ALLOCATOR ) ;
182+ }
183+ }
184+
185+ /// @brief Function for loading configuration directly into IPC peripheral.
186+ ///
187+ /// @param p_config Pointer to the structure with the initial configuration.
188+ #[ no_mangle]
189+ pub extern "C" fn nrfx_ipc_config_load ( p_config : * const NrfxIpcConfig ) {
190+ unsafe {
191+ let config: & NrfxIpcConfig = & * p_config;
192+ debug ! ( "nrfx_ipc_config_load({:?})" , config) ;
193+
194+ let ipc = & ( * nrf9160_pac:: IPC_NS :: ptr ( ) ) ;
195+
196+ for ( i, value) in config. send_task_config . iter ( ) . enumerate ( ) {
197+ ipc. send_cnf [ i as usize ] . write ( |w| w. bits ( * value) ) ;
198+ }
199+
200+ for ( i, value) in config. receive_event_config . iter ( ) . enumerate ( ) {
201+ ipc. receive_cnf [ i as usize ] . write ( |w| w. bits ( * value) ) ;
202+ }
203+
204+ ipc. intenset
205+ . write ( |w| w. bits ( config. receive_events_enabled ) ) ;
206+ }
207+ }
208+
209+ ///
210+ /// @brief Function for initializing the IPC driver.
211+ ///
212+ /// @param irq_priority Interrupt priority.
213+ /// @param handler Event handler provided by the user. Cannot be NULL.
214+ /// @param p_context Context passed to event handler.
215+ ///
216+ /// @retval NRFX_SUCCESS Initialization was successful.
217+ /// @retval NRFX_ERROR_INVALID_STATE Driver is already initialized.
218+ #[ no_mangle]
219+ pub extern "C" fn nrfx_ipc_init (
220+ irq_priority : u8 ,
221+ handler : NrfxIpcHandler ,
222+ p_context : usize ,
223+ ) -> NrfxErr {
224+ use cortex_m:: interrupt:: InterruptNumber ;
225+ let irq = nrf9160_pac:: Interrupt :: IPC ;
226+ let irq_num = usize:: from ( irq. number ( ) ) ;
227+ unsafe {
228+ cortex_m:: peripheral:: NVIC :: unmask ( irq) ;
229+ ( * cortex_m:: peripheral:: NVIC :: ptr ( ) ) . ipr [ irq_num] . write ( irq_priority) ;
230+ }
231+ IPC_CONTEXT . store ( p_context, core:: sync:: atomic:: Ordering :: SeqCst ) ;
232+ IPC_HANDLER . store ( handler as usize , core:: sync:: atomic:: Ordering :: SeqCst ) ;
233+ // Report success
234+ NrfxErr :: Success
235+ }
236+
237+ /// Function for uninitializing the IPC module.
238+ #[ no_mangle]
239+ pub extern "C" fn nrfx_ipc_uninit ( ) {
240+ unimplemented ! ( ) ;
241+ }
242+
243+ /// Allocate some memory from the given heap.
244+ ///
245+ /// We allocate four extra bytes so that we can store the number of bytes
246+ /// requested. This will be needed later when the memory is freed.
247+ ///
248+ /// This function is safe to call from an ISR.
249+ unsafe fn generic_alloc ( num_bytes_requested : usize , heap : & crate :: WrappedHeap ) -> * mut u8 {
250+ let sizeof_usize = core:: mem:: size_of :: < usize > ( ) ;
251+ let mut result = core:: ptr:: null_mut ( ) ;
252+ cortex_m:: interrupt:: free ( |cs| {
253+ let num_bytes_allocated = num_bytes_requested + sizeof_usize;
254+ let layout =
255+ core:: alloc:: Layout :: from_size_align_unchecked ( num_bytes_allocated, sizeof_usize) ;
256+ if let Some ( ref mut inner_alloc) = * heap. borrow ( cs) . borrow_mut ( ) {
257+ match inner_alloc. allocate_first_fit ( layout) {
258+ Ok ( real_block) => {
259+ let real_ptr = real_block. as_ptr ( ) ;
260+ // We need the block size to run the de-allocation. Store it in the first four bytes.
261+ core:: ptr:: write_volatile :: < usize > ( real_ptr as * mut usize , num_bytes_allocated) ;
262+ // Give them the rest of the block
263+ result = real_ptr. add ( sizeof_usize) ;
264+ }
265+ Err ( _e) => {
266+ // Ignore
267+ }
268+ }
269+ }
270+ } ) ;
271+ result
272+ }
273+
274+ /// Free some memory back on to the given heap.
275+ ///
276+ /// First we must wind the pointer back four bytes to recover the `usize` we
277+ /// stashed during the allocation. We use this to recreate the `Layout` required
278+ /// for the `deallocate` function.
279+ ///
280+ /// This function is safe to call from an ISR.
281+ unsafe fn generic_free ( ptr : * mut u8 , heap : & crate :: WrappedHeap ) {
282+ let sizeof_usize = core:: mem:: size_of :: < usize > ( ) as isize ;
283+ cortex_m:: interrupt:: free ( |cs| {
284+ // Fetch the size from the previous four bytes
285+ let real_ptr = ptr. offset ( -sizeof_usize) ;
286+ let num_bytes_allocated = core:: ptr:: read_volatile :: < usize > ( real_ptr as * const usize ) ;
287+ let layout = core:: alloc:: Layout :: from_size_align_unchecked (
288+ num_bytes_allocated,
289+ sizeof_usize as usize ,
290+ ) ;
291+ if let Some ( ref mut inner_alloc) = * heap. borrow ( cs) . borrow_mut ( ) {
292+ inner_alloc. deallocate ( core:: ptr:: NonNull :: new_unchecked ( real_ptr) , layout) ;
293+ }
294+ } ) ;
295+ }
296+
297+ /// Call this when we have an IPC IRQ. Not `extern C` as its not called by the
298+ /// library, only our interrupt handler code.
299+ pub unsafe fn ipc_irq_handler ( ) {
300+ // Get the information about events that fired this interrupt
301+ let events_map = ( * nrf9160_pac:: IPC_NS :: ptr ( ) ) . intpend . read ( ) . bits ( ) as u32 ;
302+
303+ // Clear these events
304+ let mut bitmask = events_map;
305+ while bitmask != 0 {
306+ let event_idx = bitmask. trailing_zeros ( ) ;
307+ bitmask ^= 1 << event_idx;
308+ ( * nrf9160_pac:: IPC_NS :: ptr ( ) ) . events_receive [ event_idx as usize ] . write ( |w| w. bits ( 0 ) ) ;
309+ }
310+
311+ // Execute interrupt handler to provide information about events to app
312+ let handler_addr = IPC_HANDLER . load ( core:: sync:: atomic:: Ordering :: SeqCst ) ;
313+ let handler = core:: mem:: transmute :: < usize , NrfxIpcHandler > ( handler_addr) ;
314+ let context = IPC_CONTEXT . load ( core:: sync:: atomic:: Ordering :: SeqCst ) ;
315+ ( handler) ( events_map, context as * mut u8 ) ;
316+ }
0 commit comments