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