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}