Skip to content

Commit 236f885

Browse files
committed
added build capsule task
1 parent a23b2d3 commit 236f885

1 file changed

Lines changed: 121 additions & 5 deletions

File tree

docs/tock_workshop/index.md

Lines changed: 121 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,21 +86,19 @@ Every system call except yield is non-blocking. Commands that might take a long
8686

8787
The command, subscribe, and allow system calls all take a driver ID as their first parameter. This indicates which driver in the kernel that system call is intended for. Drivers are capsules that implement the system call.
8888

89-
### Capsule
90-
91-
A capsule is a kernel component acting as a device driver, or system service capsule. Capsules sit between the low-level drivers of the core kernel and use the HIL traits to interact with them, and the userspace applications, which utilize the `Syscall` interface.
92-
9389
## Hands-on Workshop
9490

9591
### Flashing the kernel
9692

97-
Initially, you will need to clone the Tock [repository](https://example.com). To compile the board kernel, you can use the `cargo flash` utility.
93+
Initially, you will need to clone the Tock [repository](https://example.com). The configuration for the various boards supported can be found in the `boards` directory. To compile the kernel, you can use the `cargo flash` utility.
9894

9995
```shell
10096
cd boards/cy8cproto_62_4343_w
10197
cargo flash
10298
```
10399

100+
Alternatively, you can use the `make flash` while inside the board's directory.
101+
104102
If you did everything correctly, you should be able to use the `tockloader listen` command to interact with the kernel. When prompted to select a serial port, pick the one that ends with `KitProg3 CMSIS-DAP`.
105103

106104
```shell
@@ -120,3 +118,121 @@ $tock
120118
```
121119

122120
### Compiling an application
121+
122+
For this task, you will have to clone the [`libtock-c`](https://example.com) repository first. Navigate to the `examples/blink` folder and take a look at the C application structure found in `main.c`. To compile the application, simply run `make`. This command will built the example applications for all target architectures supported by the library. Apps are compiled into TBFs (Tock Binary Format), and can be found in the `build/<arch>` sub-directories. Tock also generates an archive of the same app, compiled for multiple architectures, for ease of use and portability, called a TAB(Tock Application Bundle) which can be loaded using the `tockloader` utility.
123+
124+
### Flashing the application
125+
126+
Unfortunately, the board is not currently supported by the `tockloader` project, so we will have to resort to bundling the kernel and application in a single binary and flashing it. The board you are using is a dual-core, with Tock running on the **CortexM0+** core, so the correct TBF can be found at `examples/blink/build/cortex-m0/cortex-m0.tbf`. You will need to specify the path to the compiled application in the board's `Makefile`.
127+
128+
```Makefile
129+
APP=../../libtock-c/examples/sensors/build/cortex-m0/cortex-m0.tbf
130+
```
131+
132+
Then, run the `make program` command in terminal. It will use the `arm-none-eabi-objcopy` to merge the two binaries, and load it on the board. After the binary is flashed, you should see the on board LED blinking, and you should be able to see `blink` in the apps list, using `tockloader listen`.
133+
134+
```sh
135+
tockloader listen
136+
[INFO ] No device name specified. Using default name "tock".
137+
[INFO ] No serial port with device name "tock" found.
138+
[INFO ] Found 2 serial ports.
139+
Multiple serial port options found. Which would you like to use?
140+
[0] /dev/cu.debug-console - n/a
141+
[1] /dev/cu.usbmodem1103 - KitProg3 CMSIS-DAP
142+
143+
Which option? [0] 1
144+
[INFO ] Using "/dev/cu.usbmodem1103 - KitProg3 CMSIS-DAP".
145+
[INFO ] Listening for serial output
146+
147+
$tock list
148+
149+
TODO: add app list output
150+
```
151+
152+
### Building a capsule
153+
154+
A capsule is a kernel component acting as a device driver, or system service capsule. Capsules sit between the low-level drivers of the core kernel and use the HIL traits to interact with them, and the userspace applications, which utilizes its `SyscallDriver` interface. For this task, we will build a `MockCapsule`, that will print a debug message on application command.
155+
156+
The first step is to define the `MockCapsule` driver, and implement the `SyscallDriver`. You can create a new module in the `capsules/extra` crate named `mock.rs`. We also will need to chose an unused driver number to use (`0x9000A` will work).
157+
158+
```Rust title="capsule/extra/mock.rs"
159+
use kernel::{
160+
syscall::{CommandReturn, SyscallDriver},
161+
ErrorCode,
162+
};
163+
164+
const DRIVER_NUM: usize = 0x9000A;
165+
166+
struct MockCapsule;
167+
168+
impl SyscallDriver for MockCapsule {
169+
fn command(
170+
&self,
171+
command_num: usize,
172+
_: usize,
173+
_: usize,
174+
_process_id: kernel::ProcessId,
175+
) -> kernel::syscall::CommandReturn {
176+
match command_num {
177+
_ => CommandReturn::failure(ErrorCode::NOSUPPORT),
178+
}
179+
}
180+
181+
fn allocate_grant(&self, _process_id: kernel::ProcessId) -> Result<(), kernel::process::Error> {
182+
// No-op implementation
183+
Ok(())
184+
}
185+
}
186+
```
187+
188+
:::note Module definition
189+
Do not forget to add `pub mod mock;` in the crate's `lib.rs` file.
190+
:::
191+
192+
The next step is to implement the handling of specific commands. The convention is that the first command (`0`) to be an *"exists"* command, that is usually used to check wether a driver is present or not in the board configuration, and it should simply return a `CommandReturn::success()`.
193+
194+
We also need to add our print command, on command number `1`. For serial debug printing, the kernel exposes two macros, `kernel::debug!` and `kernel::debug_verbose!`. Try to use both of them and spot the difference.
195+
196+
With our capsule implementation done, we need to add it to the board's configuration. We need to add a field for the capsule in the board's `Cy8cproto0624343w` structure.
197+
198+
```rust title="boards/cy8cproto_62_4343_w/main.rs"
199+
/// Supported drivers by the platform
200+
pub struct Cy8cproto0624343w {
201+
// ... Previous lines removed for simplicity
202+
systick: cortexm0p::systick::SysTick,
203+
// highlight-next-line
204+
mock_capsule: &'static capsules_extra::mock::MockCapsule,
205+
}
206+
207+
impl SyscallDriverLookup for Cy8cproto0624343w {
208+
fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
209+
where
210+
F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
211+
{
212+
match driver_num {
213+
// ...
214+
capsules_core::gpio::DRIVER_NUM => f(Some(self.gpio)),
215+
// highlight-next-line
216+
capsules_extra::mock::DRIVER_NUM => f(Some(self.mock_capsule)),
217+
_ => f(None),
218+
}
219+
}
220+
}
221+
222+
// ...
223+
224+
pub unsafe fn main() {
225+
// ...
226+
227+
let cy8cproto0624343w = Cy8cproto0624343w {
228+
// ...
229+
gpio,
230+
// Currently, the CPU runs at 8MHz, that being the frequency of the IMO.
231+
systick: cortexm0p::systick::SysTick::new_with_calibration(8_000_000),
232+
// highlight-next-line
233+
mock_capsule: &capsules_extra::mock::MockCapsule,
234+
};
235+
236+
// ...
237+
}
238+
```

0 commit comments

Comments
 (0)