capsules_extra/
can.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// Copyright OxidOS Automotive SRL 2022
5//
6// Author: Teona Severin <teona.severin@oxidos.io>
7
8//! Syscall driver capsule for CAN communication.
9//!
10//! This module has a CAN syscall driver capsule implementation.
11//!
12//! This capsule sends commands from the userspace to a driver that
13//! implements the Can trait.
14//!
15//! The capsule shares 2 buffers with the userspace: one RO that is used
16//! for transmitting messages and one RW that is used for receiving
17//! messages.
18//!
19//! The RO buffer uses the first 4 bytes as a counter of how many messages
20//! the userspace must read, at the time the upcall was sent. If the
21//! userspace is slower and in the meantime there were other messages
22//! that were received, the userspace reads them all and sends to the
23//! capsule a new buffer that has the counter on the first 4 bytes 0.
24//! Because of that, when receiving a callback from the driver regarding
25//! a received message, the capsule checks the counter:
26//! - if it's 0, the message will be copied to the RW buffer, the counter
27//!   will be incremented and an upcall will be sent
28//! - if it's greater the 0, the message will be copied to the RW buffer
29//!   but no upcall will be done
30//!
31//! Usage
32//! -----
33//!
34//! You need a driver that implements the Can trait.
35//! ```rust,ignore
36//! let grant_cap = create_capability!(capabilities::MemoryAllocationCapability);
37//! let grant_can = self.board_kernel.create_grant(
38//!     capsules::can::CanCapsule::DRIVER_NUM, &grant_cap);
39//! let can = capsules::can::CanCapsule::new(
40//!    can_peripheral,
41//!    grant_can,
42//!    tx_buffer,
43//!    rx_buffer,
44//! );
45//!
46//! kernel::hil::can::Controller::set_client(can_peripheral, Some(can));
47//! kernel::hil::can::Transmit::set_client(can_peripheral, Some(can));
48//! kernel::hil::can::Receive::set_client(can_peripheral, Some(can));
49//! ```
50//!
51
52use core::mem::size_of;
53
54use kernel::grant::{AllowRoCount, AllowRwCount, Grant, UpcallCount};
55use kernel::hil::can;
56use kernel::processbuffer::{ReadableProcessBuffer, WriteableProcessBuffer};
57use kernel::syscall::{CommandReturn, SyscallDriver};
58use kernel::utilities::cells::{OptionalCell, TakeCell};
59use kernel::utilities::streaming_process_slice::StreamingProcessSlice;
60use kernel::ErrorCode;
61use kernel::ProcessId;
62
63use capsules_core::driver;
64pub const DRIVER_NUM: usize = driver::NUM::Can as usize;
65pub const BYTE4_MASK: usize = 0xff000000;
66pub const BYTE3_MASK: usize = 0xff0000;
67pub const BYTE2_MASK: usize = 0xff00;
68pub const BYTE1_MASK: usize = 0xff;
69
70mod error_upcalls {
71    pub const ERROR_TX: usize = 100;
72    pub const ERROR_RX: usize = 101;
73}
74
75mod up_calls {
76    pub const UPCALL_ENABLE: usize = 0;
77    pub const UPCALL_DISABLE: usize = 1;
78    pub const UPCALL_MESSAGE_SENT: usize = 2;
79    pub const UPCALL_MESSAGE_RECEIVED: usize = 3;
80    pub const UPCALL_RECEIVED_STOPPED: usize = 4;
81    pub const UPCALL_TRANSMISSION_ERROR: usize = 5;
82    pub const COUNT: u8 = 6;
83}
84
85mod ro_allow {
86    pub const RO_ALLOW_BUFFER: usize = 0;
87    pub const COUNT: u8 = 1;
88}
89
90mod rw_allow {
91    pub const RW_ALLOW_BUFFER: usize = 0;
92    pub const COUNT: u8 = 1;
93}
94
95pub struct CanCapsule<'a, Can: can::Can> {
96    // CAN driver
97    can: &'a Can,
98
99    // CAN buffers
100    can_tx: TakeCell<'static, [u8; can::STANDARD_CAN_PACKET_SIZE]>,
101    can_rx: TakeCell<'static, [u8; can::STANDARD_CAN_PACKET_SIZE]>,
102
103    // Process
104    processes: Grant<
105        App,
106        UpcallCount<{ up_calls::COUNT }>,
107        AllowRoCount<{ ro_allow::COUNT }>,
108        AllowRwCount<{ rw_allow::COUNT }>,
109    >,
110    processid: OptionalCell<ProcessId>,
111
112    // Variable used to store the current state of the CAN peripheral
113    // during an `enable` or `disable` command.
114    peripheral_state: OptionalCell<can::State>,
115}
116
117#[derive(Default)]
118pub struct App {
119    lost_messages: u32,
120}
121
122impl<'a, Can: can::Can> CanCapsule<'a, Can> {
123    pub fn new(
124        can: &'a Can,
125        grant: Grant<
126            App,
127            UpcallCount<{ up_calls::COUNT }>,
128            AllowRoCount<{ ro_allow::COUNT }>,
129            AllowRwCount<{ rw_allow::COUNT }>,
130        >,
131        can_tx: &'static mut [u8; can::STANDARD_CAN_PACKET_SIZE],
132        can_rx: &'static mut [u8; can::STANDARD_CAN_PACKET_SIZE],
133    ) -> CanCapsule<'a, Can> {
134        CanCapsule {
135            can,
136            can_tx: TakeCell::new(can_tx),
137            can_rx: TakeCell::new(can_rx),
138            processes: grant,
139            peripheral_state: OptionalCell::empty(),
140            processid: OptionalCell::empty(),
141        }
142    }
143
144    fn schedule_callback(&self, callback_number: usize, data: (usize, usize, usize)) {
145        self.processid.map(|processid| {
146            let _ = self.processes.enter(processid, |_app, kernel_data| {
147                let _ = kernel_data.schedule_upcall(callback_number, (data.0, data.1, data.2));
148            });
149        });
150    }
151
152    /// This function makes a copy of the buffer in the grant and sends it
153    /// to the low-level hardware, in order for it to be sent on the bus.
154    pub fn process_send_command(
155        &self,
156        processid: ProcessId,
157        id: can::Id,
158        length: usize,
159    ) -> Result<(), ErrorCode> {
160        self.processes
161            .enter(processid, |_, kernel_data| {
162                kernel_data
163                    .get_readonly_processbuffer(ro_allow::RO_ALLOW_BUFFER)
164                    .map_or_else(
165                        |err| err.into(),
166                        |buffer_ref| {
167                            buffer_ref
168                                .enter(|buffer| {
169                                    self.can_tx.take().map_or(
170                                        Err(ErrorCode::NOMEM),
171                                        |dest_buffer| {
172                                            for i in 0..length {
173                                                dest_buffer[i] = buffer[i].get();
174                                            }
175                                            match self.can.send(id, dest_buffer, length) {
176                                                Ok(()) => Ok(()),
177                                                Err((err, buf)) => {
178                                                    self.can_tx.replace(buf);
179                                                    Err(err)
180                                                }
181                                            }
182                                        },
183                                    )
184                                })
185                                .unwrap_or_else(|err| err.into())
186                        },
187                    )
188            })
189            .unwrap_or_else(|err| err.into())
190    }
191
192    pub fn is_valid_process(&self, processid: ProcessId) -> bool {
193        self.processid.map_or(true, |owning_process| {
194            self.processes
195                .enter(owning_process, |_, _| owning_process == processid)
196                .unwrap_or(true)
197        })
198    }
199}
200
201impl<Can: can::Can> SyscallDriver for CanCapsule<'_, Can> {
202    fn command(
203        &self,
204        command_num: usize,
205        arg1: usize,
206        arg2: usize,
207        processid: ProcessId,
208    ) -> CommandReturn {
209        // This driver exists.
210        if command_num == 0 {
211            return CommandReturn::success();
212        }
213
214        // Check to see if the process or no process at all
215        // owns the capsule. Only one application can use the
216        // capsule at a time.
217        if !self.is_valid_process(processid) {
218            return CommandReturn::failure(ErrorCode::RESERVE);
219        } else {
220            self.processid.set(processid);
221        }
222
223        match command_num {
224            // Set the bitrate
225            1 => match self.can.set_bitrate(arg1 as u32) {
226                Ok(()) => CommandReturn::success(),
227                Err(err) => CommandReturn::failure(err),
228            },
229
230            // Set the operation mode (Loopback, Monitoring, etc)
231            2 => {
232                match self.can.set_operation_mode(match arg1 {
233                    0 => can::OperationMode::Loopback,
234                    1 => can::OperationMode::Monitoring,
235                    2 => can::OperationMode::Freeze,
236                    _ => can::OperationMode::Normal,
237                }) {
238                    Ok(()) => CommandReturn::success(),
239                    Err(err) => CommandReturn::failure(err),
240                }
241            }
242
243            // Enable the peripheral
244            3 => match self.can.enable() {
245                Ok(()) => CommandReturn::success(),
246                Err(err) => CommandReturn::failure(err),
247            },
248
249            // Disable the peripheral
250            4 => match self.can.disable() {
251                Ok(()) => CommandReturn::success(),
252                Err(err) => CommandReturn::failure(err),
253            },
254
255            // Send a message with a 16-bit identifier
256            5 => {
257                let id = can::Id::Standard(arg1 as u16);
258                self.processid
259                    .map_or(
260                        CommandReturn::failure(ErrorCode::BUSY),
261                        |processid| match self.process_send_command(processid, id, arg2) {
262                            Ok(()) => CommandReturn::success(),
263                            Err(err) => CommandReturn::failure(err),
264                        },
265                    )
266            }
267
268            // Send a message with a 32-bit identifier
269            6 => {
270                let id = can::Id::Extended(arg1 as u32);
271                self.processid
272                    .map_or(
273                        CommandReturn::failure(ErrorCode::BUSY),
274                        |processid| match self.process_send_command(processid, id, arg2) {
275                            Ok(()) => CommandReturn::success(),
276                            Err(err) => CommandReturn::failure(err),
277                        },
278                    )
279            }
280
281            // Start receiving messages
282            7 => {
283                self.can_rx
284                    .take()
285                    .map_or(CommandReturn::failure(ErrorCode::NOMEM), |dest_buffer| {
286                        self.processes
287                            .enter(processid, |_, kernel| {
288                                match kernel.get_readwrite_processbuffer(0).map_or_else(
289                                    |err| err.into(),
290                                    |buffer_ref| {
291                                        buffer_ref
292                                            .enter(|buffer| {
293                                                // make sure that the receiving buffer can have at least
294                                                // 2 messages of 8 bytes each and 4 another bytes for the counter
295                                                if buffer.len()
296                                                    >= 2 * can::STANDARD_CAN_PACKET_SIZE
297                                                        + size_of::<u32>()
298                                                {
299                                                    Ok(())
300                                                } else {
301                                                    Err(ErrorCode::SIZE)
302                                                }
303                                            })
304                                            .unwrap_or_else(|err| err.into())
305                                    },
306                                ) {
307                                    Ok(()) => match self.can.start_receive_process(dest_buffer) {
308                                        Ok(()) => CommandReturn::success(),
309                                        Err((err, _)) => CommandReturn::failure(err),
310                                    },
311                                    Err(err) => CommandReturn::failure(err),
312                                }
313                            })
314                            .unwrap_or_else(|err| err.into())
315                    })
316            }
317
318            // Stop receiving messages
319            8 => match self.can.stop_receive() {
320                Ok(()) => CommandReturn::success(),
321                Err(err) => CommandReturn::failure(err),
322            },
323
324            // Set the timing parameters
325            9 => {
326                match self.can.set_bit_timing(can::BitTiming {
327                    segment1: ((arg1 & BYTE4_MASK) >> 24) as u8,
328                    segment2: ((arg1 & BYTE3_MASK) >> 16) as u8,
329                    propagation: arg2 as u8,
330                    sync_jump_width: ((arg1 & BYTE2_MASK) >> 8) as u32,
331                    baud_rate_prescaler: (arg1 & BYTE1_MASK) as u32,
332                }) {
333                    Ok(()) => CommandReturn::success(),
334                    Err(err) => CommandReturn::failure(err),
335                }
336            }
337
338            _ => CommandReturn::failure(ErrorCode::NOSUPPORT),
339        }
340    }
341
342    fn allocate_grant(&self, process_id: ProcessId) -> Result<(), kernel::process::Error> {
343        self.processes.enter(process_id, |_, _| {})
344    }
345}
346
347impl<Can: can::Can> can::ControllerClient for CanCapsule<'_, Can> {
348    // This callback must be called after an `enable` or `disable` command was sent.
349    // It stores the new state of the peripheral.
350    fn state_changed(&self, state: can::State) {
351        self.peripheral_state.replace(state);
352    }
353
354    // This callback must be called after an `enable` command was sent and after a
355    // `state_changed` callback was called. If there is no error and the state of
356    // the peripheral is Running, send to the userspace a success callback.
357    // If the state is different or the status is an error, send to the userspace an
358    // error callback.
359    fn enabled(&self, status: Result<(), ErrorCode>) {
360        match status {
361            Ok(()) => match self.peripheral_state.take() {
362                Some(can::State::Running) => {
363                    self.schedule_callback(up_calls::UPCALL_ENABLE, (0, 0, 0));
364                }
365                Some(can::State::Error(err)) => {
366                    self.schedule_callback(up_calls::UPCALL_ENABLE, (err as usize, 0, 0));
367                }
368                Some(can::State::Disabled) | None => {
369                    self.schedule_callback(
370                        up_calls::UPCALL_ENABLE,
371                        (ErrorCode::OFF as usize, 0, 0),
372                    );
373                }
374            },
375            Err(err) => {
376                self.peripheral_state.take();
377                self.schedule_callback(up_calls::UPCALL_ENABLE, (err as usize, 0, 0));
378            }
379        }
380    }
381
382    // This callback must be called after an `disable` command was sent and after a
383    // `state_changed` callback was called. If there is no error and  the state of
384    // the peripheral is Disabled, send to the userspace a success callback.
385    // If the state is different or the status is an error, send to the userspace an
386    // error callback.
387    fn disabled(&self, status: Result<(), ErrorCode>) {
388        match status {
389            Ok(()) => match self.peripheral_state.take() {
390                Some(can::State::Disabled) => {
391                    self.schedule_callback(up_calls::UPCALL_DISABLE, (0, 0, 0));
392                }
393                Some(can::State::Error(err)) => {
394                    self.schedule_callback(up_calls::UPCALL_DISABLE, (err as usize, 0, 0));
395                }
396                Some(can::State::Running) | None => {
397                    self.schedule_callback(
398                        up_calls::UPCALL_DISABLE,
399                        (ErrorCode::FAIL as usize, 0, 0),
400                    );
401                }
402            },
403            Err(err) => {
404                self.peripheral_state.take();
405                self.schedule_callback(up_calls::UPCALL_ENABLE, (err as usize, 0, 0));
406            }
407        }
408        self.processid.clear();
409    }
410}
411
412impl<Can: can::Can> can::TransmitClient<{ can::STANDARD_CAN_PACKET_SIZE }> for CanCapsule<'_, Can> {
413    // This callback is called when the hardware acknowledges that a message
414    // was sent. This callback also makes an upcall to the userspace.
415    fn transmit_complete(
416        &self,
417        status: Result<(), can::Error>,
418        buffer: &'static mut [u8; can::STANDARD_CAN_PACKET_SIZE],
419    ) {
420        self.can_tx.replace(buffer);
421        match status {
422            Ok(()) => self.schedule_callback(up_calls::UPCALL_MESSAGE_SENT, (0, 0, 0)),
423            Err(err) => {
424                self.schedule_callback(
425                    up_calls::UPCALL_TRANSMISSION_ERROR,
426                    (error_upcalls::ERROR_TX, err as usize, 0),
427                );
428            }
429        }
430    }
431}
432
433impl<Can: can::Can> can::ReceiveClient<{ can::STANDARD_CAN_PACKET_SIZE }> for CanCapsule<'_, Can> {
434    // This callback is called when a new message is received on any receiving
435    // fifo.
436    fn message_received(
437        &self,
438        id: can::Id,
439        buffer: &mut [u8; can::STANDARD_CAN_PACKET_SIZE],
440        _len: usize,
441        status: Result<(), can::Error>,
442    ) {
443        match status {
444            Ok(()) => {
445                let res: Result<(bool, u32), ErrorCode> =
446                    self.processid.map_or(Err(ErrorCode::NOMEM), |processid| {
447                        self.processes
448                            .enter(processid, |app_data, kernel_data| {
449                                kernel_data
450                                    .get_readwrite_processbuffer(rw_allow::RW_ALLOW_BUFFER)
451                                    .map_or_else(
452                                        |err| Err(err.into()),
453                                        |buffer_ref| {
454                                            buffer_ref
455                                                .mut_enter(|user_slice| {
456                                                    StreamingProcessSlice::new(user_slice)
457                                                        .append_chunk(buffer)
458                                                        .inspect_err(|_err| {
459                                                            app_data.lost_messages += 1;
460                                                        })
461                                                })
462                                                .unwrap_or_else(|err| Err(err.into()))
463                                        },
464                                    )
465                            })
466                            .unwrap_or_else(|err| Err(err.into()))
467                    });
468
469                match res {
470                    Err(err) => self.schedule_callback(
471                        up_calls::UPCALL_TRANSMISSION_ERROR,
472                        (error_upcalls::ERROR_RX, err as usize, 0),
473                    ),
474                    Ok((_first_chunk, new_offset)) => self.schedule_callback(
475                        up_calls::UPCALL_MESSAGE_RECEIVED,
476                        (
477                            0,
478                            new_offset as usize,
479                            match id {
480                                can::Id::Standard(u16) => u16 as usize,
481                                can::Id::Extended(u32) => u32 as usize,
482                            },
483                        ),
484                    ),
485                }
486            }
487            Err(err) => {
488                let kernel_err: ErrorCode = err.into();
489                self.schedule_callback(
490                    up_calls::UPCALL_TRANSMISSION_ERROR,
491                    (error_upcalls::ERROR_RX, kernel_err.into(), 0),
492                )
493            }
494        }
495    }
496
497    fn stopped(&self, buffer: &'static mut [u8; can::STANDARD_CAN_PACKET_SIZE]) {
498        self.can_rx.replace(buffer);
499        self.schedule_callback(up_calls::UPCALL_RECEIVED_STOPPED, (0, 0, 0));
500    }
501}