Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
52b3f12
kernel: add `map` to AppSlice interface
ppannuto Jan 29, 2021
6f85074
nrf51822_serialization: port to 2.0 interface
ppannuto Jan 29, 2021
0446d99
Merge branch 'tock-2.0-dev' of github.com:tock/tock into nrf-serializ…
phil-levis Feb 9, 2021
e664b12
Updating to use map_or to detect proper lengths.
phil-levis Feb 10, 2021
4ed8309
Formatting.
phil-levis Feb 10, 2021
823e463
capsules: nrf-serialization: no recv length
bradjc Feb 12, 2021
f3de6ff
Update capsules/src/nrf51822_serialization.rs
ppannuto Feb 12, 2021
846789b
ble-uart app in libtock-c now works.
phil-levis Feb 14, 2021
37a4deb
Merge branch 'nrf-serialization-2.0' of github.com:tock/tock into nrf…
phil-levis Feb 14, 2021
7df42c7
Update capsules/src/nrf51822_serialization.rs
phil-levis Feb 15, 2021
f9a79bf
Cut the map methods.
phil-levis Feb 15, 2021
1ffd5de
Merge branch 'nrf-serialization-2.0' of github.com:tock/tock into nrf…
phil-levis Feb 15, 2021
342396c
Transitions the nRF51 syscall capsule to the 2.0 APIs. Changes the
phil-levis Feb 15, 2021
7639fcd
Merge branch 'nrf-serialization-2.0' of github.com:tock/tock into nrf…
phil-levis Feb 15, 2021
2625116
Revert "Transitions the nRF51 syscall capsule to the 2.0 APIs. Change…
phil-levis Feb 15, 2021
562b32e
Revert "Merge branch 'nrf-serialization-2.0' of github.com:tock/tock …
phil-levis Feb 15, 2021
aaa3b43
Revert "Revert "Merge branch 'nrf-serialization-2.0' of github.com:to…
phil-levis Feb 15, 2021
d70c0c0
Revert "Revert "Transitions the nRF51 syscall capsule to the 2.0 APIs…
phil-levis Feb 15, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion boards/hail/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ impl Platform for Hail {

capsules::alarm::DRIVER_NUM => f(Some(Ok(self.alarm))),
capsules::spi_controller::DRIVER_NUM => f(Some(Ok(self.spi))),
capsules::nrf51822_serialization::DRIVER_NUM => f(Some(Err(self.nrf51822))),
capsules::nrf51822_serialization::DRIVER_NUM => f(Some(Ok(self.nrf51822))),
capsules::ambient_light::DRIVER_NUM => f(Some(Ok(self.ambient_light))),
capsules::adc::DRIVER_NUM => f(Some(Ok(self.adc))),
capsules::led::DRIVER_NUM => f(Some(Ok(self.led))),
Expand Down
2 changes: 1 addition & 1 deletion boards/imix/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ impl kernel::Platform for Imix {
capsules::usb::usb_user::DRIVER_NUM => f(Some(Ok(self.usb_driver))),
capsules::ieee802154::DRIVER_NUM => f(Some(Ok(self.radio_driver))),
capsules::net::udp::DRIVER_NUM => f(Some(Ok(self.udp_driver))),
capsules::nrf51822_serialization::DRIVER_NUM => f(Some(Err(self.nrf51822))),
capsules::nrf51822_serialization::DRIVER_NUM => f(Some(Ok(self.nrf51822))),
capsules::nonvolatile_storage_driver::DRIVER_NUM => {
f(Some(Ok(self.nonvolatile_storage)))
}
Expand Down
153 changes: 98 additions & 55 deletions capsules/src/nrf51822_serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,20 @@ use core::cmp;
use kernel::common::cells::{OptionalCell, TakeCell};
use kernel::hil;
use kernel::hil::uart;
use kernel::{AppId, AppSlice, Callback, Grant, LegacyDriver, ReturnCode, SharedReadWrite};
use kernel::{
AppId, Callback, CommandResult, Driver, ErrorCode, Grant, Read, ReadOnlyAppSlice, ReadWrite,
ReadWriteAppSlice, ReturnCode,
};

/// Syscall driver number.
use crate::driver;
pub const DRIVER_NUM: usize = driver::NUM::Nrf51822Serialization as usize;

#[derive(Default)]
pub struct App {
callback: Option<Callback>,
tx_buffer: Option<AppSlice<SharedReadWrite, u8>>,
rx_buffer: Option<AppSlice<SharedReadWrite, u8>>,
callback: Callback,
tx_buffer: ReadOnlyAppSlice,
rx_buffer: ReadWriteAppSlice,
rx_recv_so_far: usize, // How many RX bytes we have currently received.
rx_recv_total: usize, // The total number of bytes we expect to receive.
}
Expand Down Expand Up @@ -95,7 +98,7 @@ impl<'a> Nrf51822Serialization<'a> {
}
}

impl LegacyDriver for Nrf51822Serialization<'_> {
impl Driver for Nrf51822Serialization<'_> {
/// Pass application space memory to this driver.
///
/// This also sets which app is currently using this driver. Only one app
Expand All @@ -104,38 +107,67 @@ impl LegacyDriver for Nrf51822Serialization<'_> {
/// ### `allow_num`
///
/// - `0`: Provide a RX buffer.
/// - `1`: Provide a TX buffer.
fn allow_readwrite(
&self,
appid: AppId,
allow_type: usize,
slice: Option<AppSlice<SharedReadWrite, u8>>,
) -> ReturnCode {
match allow_type {
mut slice: ReadWriteAppSlice,
) -> Result<ReadWriteAppSlice, (ReadWriteAppSlice, ErrorCode)> {
let res = match allow_type {
// Provide an RX buffer.
0 => {
self.active_app.set(appid);
self.apps
.enter(appid, |app, _| {
app.rx_buffer = slice;
app.rx_recv_so_far = 0;
app.rx_recv_total = 0;
ReturnCode::SUCCESS
core::mem::swap(&mut app.rx_buffer, &mut slice);
})
.unwrap_or(ReturnCode::FAIL)
.map_err(ErrorCode::from)
}

_ => Err(ErrorCode::NOSUPPORT),
};

if let Err(e) = res {
Err((slice, e))
} else {
Ok(slice)
}
}

/// Pass application space memory to this driver.
///
/// This also sets which app is currently using this driver. Only one app
/// can control the nRF51 serialization driver.
///
/// ### `allow_num`
///
/// - `0`: Provide a TX buffer.
fn allow_readonly(
&self,
appid: AppId,
allow_type: usize,
mut slice: ReadOnlyAppSlice,
) -> Result<ReadOnlyAppSlice, (ReadOnlyAppSlice, ErrorCode)> {
let res = match allow_type {
// Provide a TX buffer.
1 => {
0 => {
self.active_app.set(appid);
self.apps
.enter(appid, |app, _| {
app.tx_buffer = slice;
ReturnCode::SUCCESS
core::mem::swap(&mut app.tx_buffer, &mut slice)
})
.unwrap_or(ReturnCode::FAIL)
.map_err(ErrorCode::from)
}
_ => ReturnCode::ENOSUPPORT,

_ => Err(ErrorCode::NOSUPPORT),
};

if let Err(e) = res {
Err((slice, e))
} else {
Ok(slice)
}
}

Expand All @@ -150,27 +182,25 @@ impl LegacyDriver for Nrf51822Serialization<'_> {
fn subscribe(
&self,
subscribe_type: usize,
callback: Option<Callback>,
mut callback: Callback,
appid: AppId,
) -> ReturnCode {
) -> Result<Callback, (Callback, ErrorCode)> {
match subscribe_type {
// Add a callback
0 => {
// Save the callback for the app.
let _ = self.apps.enter(appid, |app, _| {
app.callback = callback;
});

// Start the receive now that we have a callback. If there is no
// buffer then the receive has already been started.
self.rx_buffer.take().map(|buffer| {
let len = buffer.len();
self.uart.receive_automatic(buffer, len, 250);
});

ReturnCode::SUCCESS
let result = self
.apps
.enter(appid, |app, _| {
core::mem::swap(&mut app.callback, &mut callback);
})
.map_err(ErrorCode::from);
match result {
Ok(()) => Ok(callback),
Err(e) => Err((callback, e)),
}
}
_ => ReturnCode::ENOSUPPORT,
_ => Err((callback, ErrorCode::NOSUPPORT)),
}
}

Expand All @@ -180,34 +210,47 @@ impl LegacyDriver for Nrf51822Serialization<'_> {
///
/// - `0`: Driver check.
/// - `1`: Send the allowed buffer to the nRF.
/// - `2`: Reset the nRF51822.
fn command(&self, command_type: usize, _: usize, _: usize, appid: AppId) -> ReturnCode {
/// - `2`: Received from the nRF into the allowed buffer.
/// - `3`: Reset the nRF51822.
fn command(&self, command_type: usize, arg1: usize, _: usize, appid: AppId) -> CommandResult {
match command_type {
0 /* check if present */ => ReturnCode::SUCCESS,
0 /* check if present */ => CommandResult::success(),

// Send a buffer to the nRF51822 over UART.
1 => {
self.apps.enter(appid, |app, _| {
app.tx_buffer.take().map_or(ReturnCode::FAIL, |slice| {
app.tx_buffer.map_or(CommandResult::failure(ErrorCode::FAIL), |slice| {
let write_len = slice.len();
self.tx_buffer.take().map_or(ReturnCode::FAIL, |buffer| {
self.tx_buffer.take().map_or(CommandResult::failure(ErrorCode::FAIL), |buffer| {
for (i, c) in slice.as_ref().iter().enumerate() {
buffer[i] = *c;
}
let (_err, _opt) = self.uart.transmit_buffer(buffer, write_len);
ReturnCode::SUCCESS
CommandResult::success()
})
})
}).unwrap_or(ReturnCode::FAIL)
}).unwrap_or(CommandResult::failure(ErrorCode::FAIL))
}
// Receive from the nRF51822
2 => {
self.rx_buffer.take().map_or(CommandResult::failure(ErrorCode::RESERVE), |buffer| {
let len = arg1;
if len > buffer.len() {
CommandResult::failure(ErrorCode::SIZE)
} else {
self.uart.receive_automatic(buffer, len, 250);
CommandResult::success_u32(len as u32)
}
})
}

// Initialize the nRF51822 by resetting it.
2 => {
3 => {
self.reset();
ReturnCode::SUCCESS
CommandResult::success()
}

_ => ReturnCode::ENOSUPPORT,
_ => CommandResult::failure(ErrorCode::NOSUPPORT),
}
}
}
Expand All @@ -221,9 +264,7 @@ impl uart::TransmitClient for Nrf51822Serialization<'_> {
self.active_app.map(|appid| {
let _ = self.apps.enter(*appid, |app, _| {
// Call the callback after TX has finished
app.callback.as_mut().map(|cb| {
cb.schedule(1, 0, 0);
});
app.callback.schedule(1, 0, 0);
});
});
}
Expand All @@ -244,24 +285,26 @@ impl uart::ReceiveClient for Nrf51822Serialization<'_> {

self.active_app.map(|appid| {
let _ = self.apps.enter(*appid, |app, _| {
app.rx_buffer = app.rx_buffer.take().map(|mut rb| {
let len = app.rx_buffer.mut_map_or(0, |rb| {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the len variable and the mut_map_or and later map_or are wrong here.

The comment below says Note: This indicates how many bytes were received by hardware, regardless of how much space (if any) was available in the buffer provided by the app.

But with the current code, if the rx_buffer is missing it will return 0 instead, and if it's too short, the later max_len will return the app's rx_buffer length, not the returned hardware length.

I think the fix is simply to remove the len variable, remove all of the _or's here, and pass rx_len in the callback below. I'm not going to push that fix without consensus though, as I think we'd be going back and forth if I did that..

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point -- then we should pass both. I assume these semantics are there for the peculiarities of the nRF serialization library? I'd therefore recommend this become

app.callback.schedule(4, rx_len, len);

Having implemented a bunch of these capsules, I've come to think that a simple map is dangerous; the situations in which you want to plug away when there's nothing there is pretty narrow. The API you describe, in which the byte count is the number received by the hardware, rather than what's in the buffer, is fine as long as there is always a buffer (of known length) there. But this map indicates that there might not be; calling map prevents you from being able to detect an error case. It might be that we do not want to dig into the nRF code to handle this case right now, but I think it doesn't speak well for the kernel if we make it impossible to handle. map_or has the advantage that it forces you to think about this -- what if the buffer isn't there?

// Figure out length to copy.
let max_len = cmp::min(rx_len, rb.len());

// Copy over data to app buffer.
self.rx_buffer.map(|buffer| {
self.rx_buffer.map_or(0, |buffer| {
for idx in 0..max_len {
rb.as_mut()[idx] = buffer[idx];
}
});
app.callback.as_mut().map(|cb| {
// Notify the serialization library in userspace about the
// received buffer.
cb.schedule(4, rx_len, 0);
});

rb
max_len
})
});

// Notify the serialization library in userspace about the
// received buffer.
//
// Note: This indicates how many bytes were received by
// hardware, regardless of how much space (if any) was
// available in the buffer provided by the app.
app.callback.schedule(4, rx_len, len);
});
});

Expand Down