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 + 0 ) ,
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+ /// st error from the library. See `bsd_os_errno_set` and
64+ /// Stores the l
1265/// `get_last_error`.
1366static LAST_ERROR : core:: sync:: atomic:: AtomicI32 = core:: sync:: atomic:: AtomicI32 :: new ( 0 ) ;
1467
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- }
68+ /// Remembers the IPC interrupt context we were given
69+ static IPC_CONTEXT : core :: sync :: atomic :: AtomicUsize = core :: sync :: atomic :: AtomicUsize :: new ( 0 ) ;
70+
71+ /// Remembers the IPC handler function we were given
72+ static IPC_HANDLER : core :: sync :: atomic :: AtomicUsize = core :: sync :: atomic :: AtomicUsize :: new ( 0 ) ;
2073
2174/// Function required by BSD library. We need to set the EGU1 interrupt.
2275#[ no_mangle]
23- pub extern "C" fn bsd_os_application_irq_set ( ) {
76+ pub extern "C" fn nrf_modem_os_application_irq_set ( ) {
2477 cortex_m:: peripheral:: NVIC :: pend ( crate :: cpu:: Interrupt :: EGU1 ) ;
2578}
2679
2780/// Function required by BSD library. We need to clear the EGU1 interrupt.
2881#[ no_mangle]
29- pub extern "C" fn bsd_os_application_irq_clear ( ) {
82+ pub extern "C" fn nrf_modem_os_application_irq_clear ( ) {
3083 cortex_m:: peripheral:: NVIC :: unpend ( crate :: cpu:: Interrupt :: EGU1 ) ;
3184}
3285
3386/// Function required by BSD library. We need to set the EGU2 interrupt.
3487#[ no_mangle]
35- pub extern "C" fn bsd_os_trace_irq_set ( ) {
88+ pub extern "C" fn nrf_modem_os_trace_irq_set ( ) {
3689 cortex_m:: peripheral:: NVIC :: pend ( crate :: cpu:: Interrupt :: EGU2 ) ;
3790}
3891
3992/// Function required by BSD library. We need to clear the EGU2 interrupt.
4093#[ no_mangle]
41- pub extern "C" fn bsd_os_trace_irq_clear ( ) {
94+ pub extern "C" fn nrf_modem_os_trace_irq_clear ( ) {
4295 cortex_m:: peripheral:: NVIC :: unpend ( crate :: cpu:: Interrupt :: EGU2 ) ;
4396}
4497
4598/// Function required by BSD library. We have no init to do.
4699#[ no_mangle]
47- pub extern "C" fn bsd_os_init ( ) {
100+ pub extern "C" fn nrf_modem_os_init ( ) {
48101 // Nothing
49102}
50103
51104/// Function required by BSD library. Stores an error code we can read later.
52105#[ no_mangle]
53- pub extern "C" fn bsd_os_errno_set ( errno : i32 ) {
106+ pub extern "C" fn nrf_modem_os_errno_set ( errno : i32 ) {
54107 LAST_ERROR . store ( errno, core:: sync:: atomic:: Ordering :: SeqCst ) ;
55108}
56109
@@ -61,7 +114,7 @@ pub fn get_last_error() -> i32 {
61114
62115/// Function required by BSD library
63116#[ no_mangle]
64- pub extern "C" fn bsd_os_timedwait ( _context : u32 , p_timeout_ms : * const i32 ) -> i32 {
117+ pub extern "C" fn nrf_modem_os_timedwait ( _context : u32 , p_timeout_ms : * const i32 ) -> i32 {
65118 let timeout_ms = unsafe { * p_timeout_ms } ;
66119 if timeout_ms < 0 {
67120 // With Zephyr, negative timeouts pend on a semaphore with K_FOREVER.
@@ -76,13 +129,201 @@ pub extern "C" fn bsd_os_timedwait(_context: u32, p_timeout_ms: *const i32) -> i
76129
77130/// Function required by BSD library
78131#[ no_mangle]
79- pub extern "C" fn bsd_os_trace_put ( _data : * const u8 , _len : u32 ) -> i32 {
132+ pub extern "C" fn nrf_modem_os_trace_put ( _data : * const u8 , _len : u32 ) -> i32 {
80133 // Do nothing
81134 0
82135}
83136
84137/// Function required by BSD library
85138#[ no_mangle]
86- pub extern "C" fn bsd_irrecoverable_error_handler ( err : u32 ) -> ! {
139+ pub extern "C" fn nrf_modem_irrecoverable_error_handler ( err : u32 ) -> ! {
87140 panic ! ( "bsd_irrecoverable_error_handler({})" , err) ;
88141}
142+
143+ /// The Modem library needs to dynamically allocate memory (a heap) for proper
144+ /// functioning. This memory is used to store the internal data structures that
145+ /// are used to manage the communication between the application core and the
146+ /// modem core. This memory is never shared with the modem core and hence, it
147+ /// can be located anywhere in the application core's RAM instead of the shared
148+ /// memory regions. This function allocates dynamic memory for the library.
149+ #[ no_mangle]
150+ pub extern "C" fn nrf_modem_os_alloc ( num_bytes : usize ) -> * mut u8 {
151+ debug ! ( "nrf_modem_os_alloc({})" , num_bytes) ;
152+ let usize_size = core:: mem:: size_of :: < usize > ( ) ;
153+ let mut result = core:: ptr:: null_mut ( ) ;
154+ unsafe {
155+ cortex_m:: interrupt:: free ( |cs| {
156+ let layout =
157+ core:: alloc:: Layout :: from_size_align_unchecked ( num_bytes + usize_size, usize_size) ;
158+ if let Some ( ref mut allocator) = * crate :: GENERIC_ALLOCATOR . borrow ( cs) . borrow_mut ( ) {
159+ match allocator. allocate_first_fit ( layout) {
160+ Ok ( block) => {
161+ // We need the block size to run the de-allocation. Store it in the first four bytes.
162+ core:: ptr:: write_volatile :: < usize > ( block. as_ptr ( ) as * mut usize , num_bytes) ;
163+ // Give them the rest of the block
164+ result = block. as_ptr ( ) . offset ( usize_size as isize ) ;
165+ }
166+ Err ( _e) => {
167+ // Ignore
168+ }
169+ }
170+ }
171+ } ) ;
172+ }
173+ result
174+ }
175+
176+ /// The Modem library needs to dynamically allocate memory (a heap) for proper
177+ /// functioning. This memory is used to store the internal data structures that
178+ /// are used to manage the communication between the application core and the
179+ /// modem core. This memory is never shared with the modem core and hence, it
180+ /// can be located anywhere in the application core's RAM instead of the shared
181+ /// memory regions. This function allocates dynamic memory for the library.
182+ #[ no_mangle]
183+ pub extern "C" fn nrf_modem_os_free ( ptr : * mut u8 ) {
184+ debug ! ( "nrf_modem_os_free({:?})" , ptr) ;
185+ let usize_size = core:: mem:: size_of :: < usize > ( ) as isize ;
186+ unsafe {
187+ cortex_m:: interrupt:: free ( |cs| {
188+ // Fetch the size from the previous four bytes
189+ let real_ptr = ptr. offset ( -usize_size) ;
190+ let num_bytes = core:: ptr:: read_volatile :: < usize > ( real_ptr as * const usize ) ;
191+ let layout =
192+ core:: alloc:: Layout :: from_size_align_unchecked ( num_bytes, usize_size as usize ) ;
193+ if let Some ( ref mut allocator) = * crate :: GENERIC_ALLOCATOR . borrow ( cs) . borrow_mut ( ) {
194+ allocator. deallocate ( core:: ptr:: NonNull :: new_unchecked ( ptr) , layout) ;
195+ }
196+ } ) ;
197+ }
198+ }
199+
200+ /// Allocate a buffer on the TX area of shared memory.
201+ ///
202+ /// @param bytes Buffer size.
203+ /// @return pointer to allocated memory
204+ #[ no_mangle]
205+ pub extern "C" fn nrf_modem_os_shm_tx_alloc ( num_bytes : usize ) -> * mut u8 {
206+ debug ! ( "nrf_modem_os_shm_tx_alloc({})" , num_bytes) ;
207+ let usize_size = core:: mem:: size_of :: < usize > ( ) ;
208+ let mut result = core:: ptr:: null_mut ( ) ;
209+ unsafe {
210+ cortex_m:: interrupt:: free ( |cs| {
211+ let layout =
212+ core:: alloc:: Layout :: from_size_align_unchecked ( num_bytes + usize_size, usize_size) ;
213+ if let Some ( ref mut allocator) = * crate :: TX_ALLOCATOR . borrow ( cs) . borrow_mut ( ) {
214+ match allocator. allocate_first_fit ( layout) {
215+ Ok ( block) => {
216+ // We need the block size to run the de-allocation. Store it in the first four bytes.
217+ core:: ptr:: write_volatile :: < usize > ( block. as_ptr ( ) as * mut usize , num_bytes) ;
218+ // Give them the rest of the block
219+ result = block. as_ptr ( ) . offset ( usize_size as isize ) ;
220+ }
221+ Err ( _e) => {
222+ // Ignore
223+ }
224+ }
225+ }
226+ } ) ;
227+ }
228+ result
229+ }
230+
231+ /// Free a shared memory buffer in the TX area.
232+ ///
233+ /// @param ptr Th buffer to free.
234+ #[ no_mangle]
235+ pub extern "C" fn nrf_modem_os_shm_tx_free ( ptr : * mut u8 ) {
236+ debug ! ( "nrf_modem_os_shm_tx_free({:?})" , ptr) ;
237+ let usize_size = core:: mem:: size_of :: < usize > ( ) as isize ;
238+ unsafe {
239+ cortex_m:: interrupt:: free ( |cs| {
240+ // Fetch the size from the previous four bytes
241+ let real_ptr = ptr. offset ( -usize_size) ;
242+ let num_bytes = core:: ptr:: read_volatile :: < usize > ( real_ptr as * const usize ) ;
243+ let layout =
244+ core:: alloc:: Layout :: from_size_align_unchecked ( num_bytes, usize_size as usize ) ;
245+ if let Some ( ref mut allocator) = * crate :: TX_ALLOCATOR . borrow ( cs) . borrow_mut ( ) {
246+ allocator. deallocate ( core:: ptr:: NonNull :: new_unchecked ( ptr) , layout) ;
247+ }
248+ } ) ;
249+ }
250+ }
251+
252+ /// @brief Function for loading configuration directly into IPC peripheral.
253+ ///
254+ /// @param p_config Pointer to the structure with the initial configuration.
255+ #[ no_mangle]
256+ pub extern "C" fn nrfx_ipc_config_load ( p_config : * const NrfxIpcConfig ) {
257+ unsafe {
258+ let config: & NrfxIpcConfig = & * p_config;
259+ debug ! ( "nrfx_ipc_config_load({:?})" , config) ;
260+
261+ let ipc = & ( * nrf9160_pac:: IPC_NS :: ptr ( ) ) ;
262+
263+ for ( i, value) in config. send_task_config . iter ( ) . enumerate ( ) {
264+ ipc. send_cnf [ i as usize ] . write ( |w| w. bits ( * value) ) ;
265+ }
266+
267+ for ( i, value) in config. receive_event_config . iter ( ) . enumerate ( ) {
268+ ipc. receive_cnf [ i as usize ] . write ( |w| w. bits ( * value) ) ;
269+ }
270+
271+ ipc. intenset
272+ . write ( |w| w. bits ( config. receive_events_enabled ) ) ;
273+ }
274+ }
275+
276+ ///
277+ /// @brief Function for initializing the IPC driver.
278+ ///
279+ /// @param irq_priority Interrupt priority.
280+ /// @param handler Event handler provided by the user. Cannot be NULL.
281+ /// @param p_context Context passed to event handler.
282+ ///
283+ /// @retval NRFX_SUCCESS Initialization was successful.
284+ /// @retval NRFX_ERROR_INVALID_STATE Driver is already initialized.
285+ #[ no_mangle]
286+ pub extern "C" fn nrfx_ipc_init (
287+ irq_priority : u8 ,
288+ handler : NrfxIpcHandler ,
289+ p_context : usize ,
290+ ) -> NrfxErr {
291+ use cortex_m:: interrupt:: InterruptNumber ;
292+ let irq = nrf9160_pac:: Interrupt :: IPC ;
293+ let irq_num = usize:: from ( irq. number ( ) ) ;
294+ unsafe {
295+ cortex_m:: peripheral:: NVIC :: unmask ( irq) ;
296+ ( * cortex_m:: peripheral:: NVIC :: ptr ( ) ) . ipr [ irq_num] . write ( irq_priority. into ( ) ) ;
297+ }
298+ IPC_CONTEXT . store ( p_context, core:: sync:: atomic:: Ordering :: SeqCst ) ;
299+ IPC_HANDLER . store ( handler as usize , core:: sync:: atomic:: Ordering :: SeqCst ) ;
300+ // Report success
301+ NrfxErr :: Success
302+ }
303+
304+ /// Function for uninitializing the IPC module.
305+ #[ no_mangle]
306+ pub extern "C" fn nrfx_ipc_uninit ( ) {
307+ unimplemented ! ( ) ;
308+ }
309+
310+ /// Call this when we have an IPC IRQ. Not `extern C` as its not called by the
311+ /// library, only our interrupt handler code.
312+ pub unsafe fn ipc_irq_handler ( ) {
313+ // Get the information about events that fired this interrupt
314+ let events_map = ( * nrf9160_pac:: IPC_NS :: ptr ( ) ) . intpend . read ( ) . bits ( ) as u32 ;
315+
316+ // Clear these events
317+ let mut bitmask = events_map;
318+ while bitmask != 0 {
319+ let event_idx = bitmask. trailing_zeros ( ) ;
320+ bitmask ^= 1 << event_idx;
321+ ( * nrf9160_pac:: IPC_NS :: ptr ( ) ) . events_receive [ event_idx as usize ] . write ( |w| w. bits ( 0 ) ) ;
322+ }
323+
324+ // Execute interrupt handler to provide information about events to app
325+ let handler_addr = IPC_HANDLER . load ( core:: sync:: atomic:: Ordering :: SeqCst ) ;
326+ let handler = core:: mem:: transmute :: < usize , NrfxIpcHandler > ( handler_addr) ;
327+ let context = IPC_CONTEXT . load ( core:: sync:: atomic:: Ordering :: SeqCst ) ;
328+ ( handler) ( events_map, context as * mut u8 ) ;
329+ }
0 commit comments