Skip to content

Commit 757f1e6

Browse files
bors[bot]ppannuto
andcommitted
Merge tock#1128
1128: Kernel doctests r=niklasad1 a=ppannuto ### Pull Request Overview This adds CI checks to validate that our example code in documentation is correct by running doctests. This also fixes up some broken documentation :) This PR is just for the kernel crate. Some notes: - Lines prefixed with `# ` in doc comments are not rendered - All fenced blocks are assumed to be rust unless stated otherwise, so rustdoc repurposes the code identifier a bit, e.g. a block with ` ```ignore ` will render as rust code but will not be tested - The peripherals docs are a bit messy to look at in source code form. Personally I think this is a shortcoming of rustdoc, but I think it's good to see an example of how you handle situations where there's a sort of "continuing example" throughout the documentation (you have to keep repeating the "hidden" code with `# `) ### Testing Strategy Compiling. ### Documentation Updated - [x] Updated the relevant files in `/docs`, or no updates are required. ### Formatting - [x] Ran `make formatall`. Co-authored-by: Pat Pannuto <[email protected]>
2 parents 6b481a7 + 27e1420 commit 757f1e6

File tree

6 files changed

+142
-43
lines changed

6 files changed

+142
-43
lines changed

Makefile

+6-2
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,16 @@ ci-travis:
4646
@printf "$$(tput bold)*****************$$(tput sgr0)\n"
4747
@printf "$$(tput bold)* CI: Libraries *$$(tput sgr0)\n"
4848
@printf "$$(tput bold)*****************$$(tput sgr0)\n"
49-
@CI=true cd libraries/tock-cells && cargo test
50-
@CI=true cd libraries/tock-register-interface && cargo test
49+
@cd libraries/tock-cells && CI=true cargo test
50+
@cd libraries/tock-register-interface && CI=true cargo test
5151
@printf "$$(tput bold)**************$$(tput sgr0)\n"
5252
@printf "$$(tput bold)* CI: Syntax *$$(tput sgr0)\n"
5353
@printf "$$(tput bold)**************$$(tput sgr0)\n"
5454
@CI=true $(MAKE) allcheck
55+
@printf "$$(tput bold)****************$$(tput sgr0)\n"
56+
@printf "$$(tput bold)* CI: DocTests *$$(tput sgr0)\n"
57+
@printf "$$(tput bold)****************$$(tput sgr0)\n"
58+
@cd kernel && CI=true TOCK_KERNEL_VERSION=ci_test cargo test
5559
@printf "$$(tput bold)*******************$$(tput sgr0)\n"
5660
@printf "$$(tput bold)* CI: Compilation *$$(tput sgr0)\n"
5761
@printf "$$(tput bold)*******************$$(tput sgr0)\n"

kernel/src/common/peripherals.rs

+97-17
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
//! Generally, Tock peripherals are modeled by two structures, such as:
88
//!
99
//! ```rust
10+
//! # use kernel::common::cells::VolatileCell;
11+
//! # use kernel::common::StaticRef;
12+
//! # struct ChipSpecificPeripheralClock {};
1013
//! /// The MMIO Structure.
1114
//! #[repr(C)]
1215
//! #[allow(dead_code)]
@@ -16,9 +19,9 @@
1619
//! }
1720
//!
1821
//! /// The Tock object that holds all information for this peripheral.
19-
//! pub struct PeripheralHardware {
22+
//! pub struct PeripheralHardware<'a> {
2023
//! mmio_address: StaticRef<PeripheralRegisters>,
21-
//! clock: &ChipSpecificPeripheralClock,
24+
//! clock: &'a ChipSpecificPeripheralClock,
2225
//! }
2326
//! ```
2427
//!
@@ -29,23 +32,57 @@
2932
//! MMIO pointer safely, Tock provides the PeripheralManager interface:
3033
//!
3134
//! ```rust
35+
//! # use kernel::common::cells::VolatileCell;
36+
//! # use kernel::common::peripherals::PeripheralManager;
37+
//! # use kernel::common::StaticRef;
38+
//! # use kernel::hil;
39+
//! # use kernel::ReturnCode;
40+
//! # struct PeripheralRegisters { control: VolatileCell<u32> };
41+
//! # struct PeripheralHardware { mmio_address: StaticRef<PeripheralRegisters> };
3242
//! impl hil::uart::UART for PeripheralHardware {
33-
//! fn init(&self, params: hil::uart::UARTParams) {
34-
//! let peripheral = &PeripheralManager::new(self);
35-
//! peripheral.registers.control.set(0x0);
36-
//! // ^^^^^^^^^-- This is type &PeripheralRegisters
43+
//! fn configure(&self, params: hil::uart::UARTParameters) -> ReturnCode {
44+
//! let peripheral = &PeripheralManager::new(self);
45+
//! peripheral.registers.control.set(0x0);
46+
//! // ^^^^^^^^^-- This is type &PeripheralRegisters
47+
//! ReturnCode::SUCCESS
48+
//! }
49+
//! # fn set_client(&self, _client: &'static hil::uart::Client) {}
50+
//! # fn transmit(&self, _tx_data: &'static mut [u8], _tx_len: usize) {}
51+
//! # fn receive(&self, _rx_buffer: &'static mut [u8], _rx_len: usize) {}
52+
//! # fn abort_receive(&self) {}
53+
//! }
54+
//! # use kernel::common::peripherals::PeripheralManagement;
55+
//! # use kernel::NoClockControl;
56+
//! # impl PeripheralManagement<NoClockControl> for PeripheralHardware {
57+
//! # type RegisterType = PeripheralRegisters;
58+
//!
59+
//! # fn get_registers(&self) -> &PeripheralRegisters {
60+
//! # &*self.mmio_address
61+
//! # }
62+
//! # fn get_clock(&self) -> &NoClockControl { unsafe { &kernel::NO_CLOCK_CONTROL } }
63+
//! # fn before_peripheral_access(&self, _c: &NoClockControl, _r: &Self::RegisterType) {}
64+
//! # fn after_peripheral_access(&self, _c: &NoClockControl, _r: &Self::RegisterType) {}
65+
//! # }
3766
//! ```
3867
//!
3968
//! Each peripheral must tell the kernel where its registers live in memory:
4069
//!
4170
//! ```rust
71+
//! # use kernel::common::peripherals::PeripheralManagement;
72+
//! # use kernel::common::StaticRef;
73+
//! # pub struct PeripheralRegisters {};
74+
//! # pub struct PeripheralHardware { mmio_address: StaticRef<PeripheralRegisters> };
4275
//! /// Teaching the kernel how to create PeripheralRegisters.
43-
//! impl PeripheralManagement<pm::Clock> for PeripheralHardware {
76+
//! use kernel::NoClockControl;
77+
//! impl PeripheralManagement<NoClockControl> for PeripheralHardware {
4478
//! type RegisterType = PeripheralRegisters;
4579
//!
4680
//! fn get_registers(&self) -> &PeripheralRegisters {
4781
//! &*self.mmio_address
4882
//! }
83+
//! # fn get_clock(&self) -> &NoClockControl { unsafe { &kernel::NO_CLOCK_CONTROL } }
84+
//! # fn before_peripheral_access(&self, _c: &NoClockControl, _r: &Self::RegisterType) {}
85+
//! # fn after_peripheral_access(&self, _c: &NoClockControl, _r: &Self::RegisterType) {}
4986
//! }
5087
//! ```
5188
//!
@@ -68,18 +105,40 @@
68105
//! without enabling clocks if needed if they use hardware for bookkeeping.
69106
//!
70107
//! ```rust
108+
//! use kernel::common::peripherals::PeripheralManagement;
109+
//! use kernel::common::StaticRef;
110+
//! use kernel::ClockInterface;
111+
//! // A dummy clock for this example.
112+
//! // Real peripherals that do not have clocks should use NoClockControl from this module.
113+
//! struct ExampleClock {};
114+
//! impl ClockInterface for ExampleClock {
115+
//! fn is_enabled(&self) -> bool { true }
116+
//! fn enable(&self) { }
117+
//! fn disable(&self) { }
118+
//! }
119+
//!
120+
//! // Dummy hardware for this example.
121+
//! struct SpiRegisters {};
122+
//! struct SpiHw<'a> {
123+
//! mmio_address: StaticRef<SpiRegisters>,
124+
//! clock: &'a ExampleClock,
125+
//! busy: bool,
126+
//! };
127+
//!
71128
//! /// Teaching the kernel which clock controls SpiHw.
72-
//! impl PeripheralManagement<pm::Clock> for SpiHw {
73-
//! fn get_clock(&self) -> &pm::Clock {
74-
//! &pm::Clock::PBA(pm::PBAClock::SPI)
75-
//! }
129+
//! impl<'a> PeripheralManagement<ExampleClock> for SpiHw<'a> {
130+
//! type RegisterType = SpiRegisters;
131+
//!
132+
//! fn get_registers(&self) -> &SpiRegisters { &*self.mmio_address }
133+
//!
134+
//! fn get_clock(&self) -> &ExampleClock { self.clock }
76135
//!
77-
//! fn before_mmio_access(&self, clock: &pm::Clock, _registers: &SpiRegisters) {
136+
//! fn before_peripheral_access(&self, clock: &ExampleClock, _registers: &SpiRegisters) {
78137
//! clock.enable();
79138
//! }
80139
//!
81-
//! fn after_mmio_access(&self, clock: &pm::Clock, _registers: &SpiRegisters) {
82-
//! if !self.is_busy() {
140+
//! fn after_peripheral_access(&self, clock: &ExampleClock, _registers: &SpiRegisters) {
141+
//! if !self.busy {
83142
//! clock.disable();
84143
//! }
85144
//! }
@@ -120,9 +179,30 @@ where
120179
/// PeripheralManagement trait) should instantiate an instance of this
121180
/// method to accesss memory mapped registers.
122181
///
123-
/// ```rust
124-
/// let peripheral = &PeripheralManager::new(self);
125-
/// peripheral.registers.control.set(0x1);
182+
/// ```
183+
/// # use kernel::common::cells::VolatileCell;
184+
/// # use kernel::common::peripherals::PeripheralManager;
185+
/// # use kernel::common::StaticRef;
186+
/// # pub struct PeripheralRegisters { control: VolatileCell<u32> };
187+
/// # pub struct PeripheralHardware { mmio_address: StaticRef<PeripheralRegisters> };
188+
/// impl PeripheralHardware {
189+
/// fn example(&self) {
190+
/// let peripheral = &PeripheralManager::new(self);
191+
/// peripheral.registers.control.set(0x1);
192+
/// }
193+
/// }
194+
/// # use kernel::common::peripherals::PeripheralManagement;
195+
/// # use kernel::NoClockControl;
196+
/// # impl PeripheralManagement<NoClockControl> for PeripheralHardware {
197+
/// # type RegisterType = PeripheralRegisters;
198+
///
199+
/// # fn get_registers(&self) -> &PeripheralRegisters {
200+
/// # &*self.mmio_address
201+
/// # }
202+
/// # fn get_clock(&self) -> &NoClockControl { unsafe { &kernel::NO_CLOCK_CONTROL } }
203+
/// # fn before_peripheral_access(&self, _c: &NoClockControl, _r: &Self::RegisterType) {}
204+
/// # fn after_peripheral_access(&self, _c: &NoClockControl, _r: &Self::RegisterType) {}
205+
/// # }
126206
/// ```
127207
pub struct PeripheralManager<'a, H, C>
128208
where

kernel/src/debug.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
//!
77
//! Before debug interfaces can be used, the board file must assign them hardware:
88
//!
9-
//! ```rust
9+
//! ```ignore
1010
//! kernel::debug::assign_gpios(
1111
//! Some(&sam4l::gpio::PA[13]),
1212
//! Some(&sam4l::gpio::PA[15]),
@@ -22,13 +22,17 @@
2222
//! Example
2323
//! -------
2424
//!
25-
//! ```rust
25+
//! ```no_run
26+
//! # #[macro_use] extern crate kernel;
27+
//! # fn main() {
28+
//! # let i = 42;
2629
//! debug!("Yes the code gets here with value {}", i);
2730
//! debug_verbose!("got here"); // includes message count, file, and line
2831
//! debug_gpio!(0, toggle); // Toggles the first debug GPIO
32+
//! # }
2933
//! ```
3034
//!
31-
//! ```
35+
//! ```text
3236
//! Yes the code gets here with value 42
3337
//! TOCK_DEBUG(0): /tock/capsules/src/sensys.rs:24: got here
3438
//! ```

kernel/src/hil/flash.rs

+20-12
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
11
//! Interface for reading, writing, and erasing flash storage pages.
22
//!
33
//! Operates on single pages. The page size is set by the associated type
4-
//! `page`. Here is an example of a page type:
4+
//! `page`. Here is an example of a page type and implementation of this trait:
55
//!
66
//! ```rust
7+
//! # #![feature(const_fn)]
8+
//! # extern crate core;
9+
//! # extern crate kernel;
10+
//! use core::ops::{Index, IndexMut};
11+
//!
12+
//! use kernel::hil;
13+
//! use kernel::ReturnCode;
14+
//!
715
//! // Size in bytes
816
//! const PAGE_SIZE: u32 = 1024;
917
//!
10-
//! pub struct NewChipPage(pub [u8; PAGE_SIZE as usize]);
18+
//! struct NewChipPage(pub [u8; PAGE_SIZE as usize]);
1119
//!
1220
//! impl NewChipPage {
1321
//! pub const fn new() -> NewChipPage {
@@ -38,34 +46,34 @@
3846
//! &mut self.0
3947
//! }
4048
//! }
41-
//! ```
4249
//!
43-
//! Then a basic implementation of this trait should look like:
50+
//! struct NewChipStruct {};
4451
//!
45-
//! ```rust
46-
//!
47-
//! impl hil::flash::HasClient for NewChipStruct {
52+
//! impl<'a, C> hil::flash::HasClient<'a, C> for NewChipStruct {
4853
//! fn set_client(&'a self, client: &'a C) { }
4954
//! }
5055
//!
5156
//! impl hil::flash::Flash for NewChipStruct {
5257
//! type Page = NewChipPage;
5358
//!
54-
//! fn read_page(&self, page_number: usize, buf: &'static mut Self::Page) -> ReturnCode { }
55-
//! fn write_page(&self, page_number: usize, buf: &'static mut Self::Page) -> ReturnCode { }
56-
//! fn erase_page(&self, page_number: usize) -> ReturnCode { }
59+
//! fn read_page(&self, page_number: usize, buf: &'static mut Self::Page) -> ReturnCode { ReturnCode::FAIL }
60+
//! fn write_page(&self, page_number: usize, buf: &'static mut Self::Page) -> ReturnCode { ReturnCode::FAIL }
61+
//! fn erase_page(&self, page_number: usize) -> ReturnCode { ReturnCode::FAIL }
5762
//! }
5863
//! ```
5964
//!
6065
//! A user of this flash interface might look like:
6166
//!
6267
//! ```rust
68+
//! use kernel::common::cells::TakeCell;
69+
//! use kernel::hil;
70+
//!
6371
//! pub struct FlashUser<'a, F: hil::flash::Flash + 'static> {
6472
//! driver: &'a F,
6573
//! buffer: TakeCell<'static, F::Page>,
6674
//! }
6775
//!
68-
//! impl<F: hil::flash::Flash > FlashUser<'a, F> {
76+
//! impl<'a, F: hil::flash::Flash> FlashUser<'a, F> {
6977
//! pub fn new(driver: &'a F, buffer: &'static mut F::Page) -> FlashUser<'a, F> {
7078
//! FlashUser {
7179
//! driver: driver,
@@ -74,7 +82,7 @@
7482
//! }
7583
//! }
7684
//!
77-
//! impl<F: hil::flash::Flash > hil::flash::Client<F> for FlashUser<'a, F> {
85+
//! impl<'a, F: hil::flash::Flash> hil::flash::Client<F> for FlashUser<'a, F> {
7886
//! fn read_complete(&self, buffer: &'static mut F::Page, error: hil::flash::Error) {}
7987
//! fn write_complete(&self, buffer: &'static mut F::Page, error: hil::flash::Error) { }
8088
//! fn erase_complete(&self, error: hil::flash::Error) {}

kernel/src/hil/rng.rs

+11-8
Original file line numberDiff line numberDiff line change
@@ -21,36 +21,39 @@
2121
//! once a second using the `Alarm` and `RNG` traits.
2222
//!
2323
//! ```
24-
//! struct RngTest<'a, A: Alarm > {
25-
//! rng: &'a RNG,
24+
//! use kernel::hil;
25+
//! use kernel::hil::time::Frequency;
26+
//!
27+
//! struct RngTest<'a, A: 'a + hil::time::Alarm> {
28+
//! rng: &'a hil::rng::RNG,
2629
//! alarm: &'a A
2730
//! }
2831
//!
29-
//! impl<A: Alarm> RngTest<'a, A> {
32+
//! impl<'a, A: hil::time::Alarm> RngTest<'a, A> {
3033
//! pub fn initialize(&self) {
3134
//! let interval = 1 * <A::Frequency>::frequency();
3235
//! let tics = self.alarm.now().wrapping_add(interval);
3336
//! self.alarm.set_alarm(tics);
3437
//! }
3538
//! }
3639
//!
37-
//! impl<A: Alarm> time::Client for RngTest<'a, A> {
40+
//! impl<'a, A: hil::time::Alarm> hil::time::Client for RngTest<'a, A> {
3841
//! fn fired(&self) {
3942
//! self.rng.get();
4043
//! }
4144
//! }
4245
//!
43-
//! impl<A: Alarm> rng::Client for RngTest<'a, A> {
44-
//! fn randomness_available(&self, randomness: &mut Iterator<Item = u32>) -> rng::Continue {
46+
//! impl<'a, A: hil::time::Alarm> hil::rng::Client for RngTest<'a, A> {
47+
//! fn randomness_available(&self, randomness: &mut Iterator<Item = u32>) -> hil::rng::Continue {
4548
//! match randomness.next() {
4649
//! Some(random) => {
4750
//! println!("Rand {}", random);
4851
//! let interval = 1 * <A::Frequency>::frequency();
4952
//! let tics = self.alarm.now().wrapping_add(interval);
5053
//! self.alarm.set_alarm(tics);
51-
//! rng::Continue::Done
54+
//! hil::rng::Continue::Done
5255
//! },
53-
//! None => rng::Continue::More
56+
//! None => hil::rng::Continue::More
5457
//! }
5558
//! }
5659
//! }

kernel/src/hil/time.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ pub trait Alarm: Time {
7272
///
7373
/// # Examples
7474
///
75-
/// ```rust
75+
/// ```ignore
7676
/// let delta = 1337;
7777
/// let tics = alarm.now().wrapping_add(delta);
7878
/// alarm.set_alarm(tics);

0 commit comments

Comments
 (0)