capsules_extra/nrf51822_serialization.rs
1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Provides userspace with the UART API that the nRF51822 serialization library
6//! requires.
7//!
8//! This capsule handles interfacing with the UART driver, and includes some
9//! nuances that keep the Nordic BLE serialization library happy.
10//!
11//! Usage
12//! -----
13//!
14//! ```rust,ignore
15//! # use kernel::{hil, static_init};
16//! # use capsules::nrf51822_serialization;
17//! # use capsules::nrf51822_serialization::Nrf51822Serialization;
18//!
19//! let nrf_serialization = static_init!(
20//! Nrf51822Serialization<usart::USART>,
21//! Nrf51822Serialization::new(&usart::USART3,
22//! &mut nrf51822_serialization::WRITE_BUF,
23//! &mut nrf51822_serialization::READ_BUF));
24//! hil::uart::UART::set_client(&usart::USART3, nrf_serialization);
25//! ```
26
27use core::cmp;
28
29use kernel::grant::{AllowRoCount, AllowRwCount, Grant, UpcallCount};
30use kernel::hil;
31use kernel::hil::uart;
32use kernel::processbuffer::{ReadableProcessBuffer, WriteableProcessBuffer};
33use kernel::syscall::{CommandReturn, SyscallDriver};
34use kernel::utilities::cells::{OptionalCell, TakeCell};
35use kernel::{ErrorCode, ProcessId};
36
37/// Syscall driver number.
38use capsules_core::driver;
39pub const DRIVER_NUM: usize = driver::NUM::Nrf51822Serialization as usize;
40
41/// IDs for subscribed upcalls.
42mod upcall {
43 /// Callback will be called when a TX finishes and when RX data is
44 /// available.
45 pub const TX_DONE_RX_READY: usize = 0;
46 /// Number of upcalls.
47 pub const COUNT: u8 = 1;
48}
49
50/// Ids for read-only allow buffers
51mod ro_allow {
52 /// TX buffer.
53 ///
54 /// This also sets which app is currently using this driver. Only one app
55 /// can control the nRF51 serialization driver.
56 pub const TX: usize = 0;
57 /// The number of allow buffers the kernel stores for this grant
58 pub const COUNT: u8 = 1;
59}
60
61/// Ids for read-write allow buffers
62mod rw_allow {
63 /// RX buffer.
64 ///
65 /// This also sets which app is currently using this driver. Only one app
66 /// can control the nRF51 serialization driver.
67 pub const RX: usize = 0;
68 /// The number of allow buffers the kernel stores for this grant
69 pub const COUNT: u8 = 1;
70}
71
72#[derive(Default)]
73pub struct App;
74
75// Local buffer for passing data between applications and the underlying
76// transport hardware.
77pub const WRITE_BUF_LEN: usize = 600;
78pub const READ_BUF_LEN: usize = 600;
79
80// We need two resources: a UART HW driver and driver state for each
81// application.
82pub struct Nrf51822Serialization<'a> {
83 uart: &'a dyn uart::UartAdvanced<'a>,
84 reset_pin: &'a dyn hil::gpio::Pin,
85 apps: Grant<
86 App,
87 UpcallCount<{ upcall::COUNT }>,
88 AllowRoCount<{ ro_allow::COUNT }>,
89 AllowRwCount<{ rw_allow::COUNT }>,
90 >,
91 active_app: OptionalCell<ProcessId>,
92 tx_buffer: TakeCell<'static, [u8]>,
93 rx_buffer: TakeCell<'static, [u8]>,
94}
95
96impl<'a> Nrf51822Serialization<'a> {
97 pub fn new(
98 uart: &'a dyn uart::UartAdvanced<'a>,
99 grant: Grant<
100 App,
101 UpcallCount<{ upcall::COUNT }>,
102 AllowRoCount<{ ro_allow::COUNT }>,
103 AllowRwCount<{ rw_allow::COUNT }>,
104 >,
105 reset_pin: &'a dyn hil::gpio::Pin,
106 tx_buffer: &'static mut [u8],
107 rx_buffer: &'static mut [u8],
108 ) -> Nrf51822Serialization<'a> {
109 Nrf51822Serialization {
110 uart,
111 reset_pin,
112 apps: grant,
113 active_app: OptionalCell::empty(),
114 tx_buffer: TakeCell::new(tx_buffer),
115 rx_buffer: TakeCell::new(rx_buffer),
116 }
117 }
118
119 pub fn initialize(&self) {
120 let _ = self.uart.configure(uart::Parameters {
121 baud_rate: 250000,
122 width: uart::Width::Eight,
123 stop_bits: uart::StopBits::One,
124 parity: uart::Parity::Even,
125 hw_flow_control: true,
126 });
127 }
128
129 pub fn reset(&self) {
130 self.reset_pin.make_output();
131 self.reset_pin.clear();
132 // minimum hold time is 200ns, ~20ns per instruction, so overshoot a bit
133 for _ in 0..10 {
134 self.reset_pin.clear();
135 }
136 self.reset_pin.set();
137 }
138}
139
140impl SyscallDriver for Nrf51822Serialization<'_> {
141 /// Issue a command to the Nrf51822Serialization driver.
142 ///
143 /// ### `command_type`
144 ///
145 /// - `0`: Driver existence check.
146 /// - `1`: Send the allowed buffer to the nRF.
147 /// - `2`: Received from the nRF into the allowed buffer.
148 /// - `3`: Reset the nRF51822.
149 fn command(
150 &self,
151 command_type: usize,
152 arg1: usize,
153 _: usize,
154 processid: ProcessId,
155 ) -> CommandReturn {
156 match command_type {
157 0 => CommandReturn::success(),
158
159 // Send a buffer to the nRF51822 over UART.
160 1 => {
161 self.apps
162 .enter(processid, |_, kernel_data| {
163 kernel_data
164 .get_readonly_processbuffer(ro_allow::TX)
165 .and_then(|tx| {
166 tx.enter(|slice| {
167 let write_len = slice.len();
168 self.tx_buffer.take().map_or(
169 CommandReturn::failure(ErrorCode::FAIL),
170 |buffer| {
171 for (i, c) in slice.iter().enumerate() {
172 buffer[i] = c.get();
173 }
174 // Set this as the active app for the transmit callback
175 self.active_app.set(processid);
176 let _ = self.uart.transmit_buffer(buffer, write_len);
177 CommandReturn::success()
178 },
179 )
180 })
181 })
182 .unwrap_or(CommandReturn::failure(ErrorCode::FAIL))
183 })
184 .unwrap_or(CommandReturn::failure(ErrorCode::FAIL))
185 }
186 // Receive from the nRF51822
187 2 => {
188 let len = arg1;
189
190 // We only allow one app to use the NRF serialization capsule
191 // (old legacy code, and a difficult thing to virtualize).
192 // However, we would like to support restarting/updating apps.
193 // But we don't want to allow a simultaneous app to disrupt the
194 // app that got to the BLE serialization first. So we have to
195 // find a compromise.
196 //
197 // We handle this by checking if the current active app still
198 // exists. If it does, we leave it alone. Otherwise, we replace
199 // it.
200 self.active_app.map_or_else(
201 || {
202 // The app is not set, handle this for the normal case.
203 self.rx_buffer.take().map_or(
204 CommandReturn::failure(ErrorCode::RESERVE),
205 |buffer| {
206 if len > buffer.len() {
207 CommandReturn::failure(ErrorCode::SIZE)
208 } else {
209 // Set this as the active app for the
210 // receive callback.
211 self.active_app.set(processid);
212 let _ = self.uart.receive_automatic(buffer, len, 250);
213 CommandReturn::success_u32(len as u32)
214 }
215 },
216 )
217 },
218 |processid| {
219 // The app is set, check if it still exists.
220 if let Err(kernel::process::Error::NoSuchApp) =
221 self.apps.enter(processid, |_, _| {})
222 {
223 // The app we had as active no longer exists.
224 self.active_app.clear();
225 self.rx_buffer.take().map_or_else(
226 || {
227 // We do not have the RF buffer as it is
228 // currently in use by the underlying UART.
229 // We don't have to do anything else except
230 // update the active app.
231 self.active_app.set(processid);
232 CommandReturn::success_u32(len as u32)
233 },
234 |buffer| {
235 if len > buffer.len() {
236 CommandReturn::failure(ErrorCode::SIZE)
237 } else {
238 self.active_app.set(processid);
239 // Use the buffer to start the receive.
240 let _ = self.uart.receive_automatic(buffer, len, 250);
241 CommandReturn::success_u32(len as u32)
242 }
243 },
244 )
245 } else {
246 // Active app exists. Return error as there can only
247 // be one app using this capsule.
248 CommandReturn::failure(ErrorCode::RESERVE)
249 }
250 },
251 )
252 }
253
254 // Initialize the nRF51822 by resetting it.
255 3 => {
256 self.reset();
257 CommandReturn::success()
258 }
259
260 _ => CommandReturn::failure(ErrorCode::NOSUPPORT),
261 }
262 }
263
264 fn allocate_grant(&self, processid: ProcessId) -> Result<(), kernel::process::Error> {
265 self.apps.enter(processid, |_, _| {})
266 }
267}
268
269// Callbacks from the underlying UART driver.
270impl uart::TransmitClient for Nrf51822Serialization<'_> {
271 // Called when the UART TX has finished.
272 fn transmitted_buffer(
273 &self,
274 buffer: &'static mut [u8],
275 _tx_len: usize,
276 _rcode: Result<(), ErrorCode>,
277 ) {
278 self.tx_buffer.replace(buffer);
279
280 self.active_app.map(|processid| {
281 let _ = self.apps.enter(processid, |_app, kernel_data| {
282 // Call the callback after TX has finished
283 kernel_data
284 .schedule_upcall(upcall::TX_DONE_RX_READY, (1, 0, 0))
285 .ok();
286 });
287 });
288 }
289
290 fn transmitted_word(&self, _rcode: Result<(), ErrorCode>) {}
291}
292
293impl uart::ReceiveClient for Nrf51822Serialization<'_> {
294 // Called when a buffer is received on the UART.
295 fn received_buffer(
296 &self,
297 buffer: &'static mut [u8],
298 rx_len: usize,
299 _rcode: Result<(), ErrorCode>,
300 _error: uart::Error,
301 ) {
302 self.rx_buffer.replace(buffer);
303
304 // By default we continuously receive on UART. However, if we receive
305 // and the active app is no longer existent, then we stop receiving.
306 let mut repeat_receive = true;
307
308 self.active_app.map(|processid| {
309 if let Err(_err) = self.apps.enter(processid, |_, kernel_data| {
310 let len = kernel_data
311 .get_readwrite_processbuffer(rw_allow::RX)
312 .and_then(|rx| {
313 rx.mut_enter(|rb| {
314 // Figure out length to copy.
315 let max_len = cmp::min(rx_len, rb.len());
316
317 // Copy over data to app buffer.
318 self.rx_buffer.map_or(0, |buffer| {
319 for idx in 0..max_len {
320 rb[idx].set(buffer[idx]);
321 }
322 max_len
323 })
324 })
325 })
326 .unwrap_or(0);
327
328 // Notify the serialization library in userspace about the
329 // received buffer.
330 //
331 // Note: This indicates how many bytes were received by
332 // hardware, regardless of how much space (if any) was
333 // available in the buffer provided by the app.
334 kernel_data
335 .schedule_upcall(upcall::TX_DONE_RX_READY, (4, rx_len, len))
336 .ok();
337 }) {
338 // The app we had as active no longer exists. Clear that and
339 // stop receiving. This puts us back in an idle state. A new app
340 // can use the BLE serialization.
341 self.active_app.clear();
342 repeat_receive = false;
343 }
344 });
345
346 if repeat_receive {
347 // Restart the UART receive.
348 self.rx_buffer.take().map(|buffer| {
349 let len = buffer.len();
350 let _ = self.uart.receive_automatic(buffer, len, 250);
351 });
352 }
353 }
354
355 fn received_word(&self, _word: u32, _rcode: Result<(), ErrorCode>, _err: uart::Error) {}
356}