Skip to content

Commit fbe6d06

Browse files
authored
Merge pull request #8 from awelkie/master
Change transfer_multiple to not copy any buffers
2 parents cc46661 + ec34575 commit fbe6d06

File tree

4 files changed

+79
-112
lines changed

4 files changed

+79
-112
lines changed

README.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,11 @@ use spidev::{Spidev, SpidevOptions, SpidevTransfer, SPI_MODE_0};
2727

2828
fn create_spi() -> io::Result<Spidev> {
2929
let mut spi = try!(Spidev::open("/dev/spidev0.0"));
30-
let mut options = SpidevOptions::new()
30+
let options = SpidevOptions::new()
3131
.bits_per_word(8)
3232
.max_speed_hz(20_000)
33-
.mode(SPI_MODE_0);
33+
.mode(SPI_MODE_0)
34+
.build();
3435
try!(spi.configure(&options));
3536
Ok(spi)
3637
}
@@ -48,9 +49,13 @@ fn half_duplex(spi: &mut Spidev) -> io::Result<()> {
4849
fn full_duplex(spi: &mut Spidev) -> io::Result<()> {
4950
// "write" transfers are also reads at the same time with
5051
// the read having the same length as the write
51-
let mut transfer = SpidevTransfer::write(&[0x01, 0x02, 0x03]);
52-
try!(spi.transfer(&mut transfer));
53-
println!("{:?}", transfer.rx_buf);
52+
let tx_buf = [0x01, 0x02, 0x03];
53+
let mut rx_buf = [0; 3];
54+
{
55+
let mut transfer = SpidevTransfer::read_write(&tx_buf, &mut rx_buf);
56+
try!(spi.transfer(&mut transfer));
57+
}
58+
println!("{:?}", rx_buf);
5459
Ok(())
5560
}
5661

examples/spidev-bidir.rs

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,6 @@ extern crate spidev;
22
use spidev::{Spidev, SpidevOptions, SPI_MODE_0};
33
use spidev::spidevioctl::SpidevTransfer;
44

5-
fn pprint_transfer(transfer: &SpidevTransfer) {
6-
match transfer.rx_buf {
7-
None => println!("Empty!"),
8-
Some(ref rx_buf) => {
9-
for b in rx_buf.iter() {
10-
print!("{:?} ", b);
11-
}
12-
println!("");
13-
}
14-
}
15-
}
16-
175
fn main() {
186
let mut spidev = Spidev::open("/dev/spidev0.0").unwrap();
197
let options = SpidevOptions::new()
@@ -25,22 +13,27 @@ fn main() {
2513
spidev.configure(&options).unwrap();
2614

2715
println!("===== Single transfer =========");
28-
let mut transfer = SpidevTransfer::write(&[0xaa, 0xbb, 0xcc, 0xdd, 0xee]);
29-
match spidev.transfer(&mut transfer) {
30-
Ok(_) => pprint_transfer(&transfer),
31-
Err(err) => println!("{:?}", err),
32-
}
16+
let tx_buf = [0xaa, 0xbb, 0xcc, 0xdd, 0xee];
17+
let mut rx_buf = [0; 5];
18+
let mut transfer = SpidevTransfer::read_write(&tx_buf, &mut rx_buf);
19+
println!("{:?}", spidev.transfer(&mut transfer));
3320

3421
println!("===== Multi Transfer =========");
35-
let transfers = vec![SpidevTransfer::read(10),
36-
SpidevTransfer::write(&[0x00, 0x01, 0x02, 0x03]),
37-
SpidevTransfer::write(&[0xff, 0xfe, 0xfd])];
38-
match spidev.transfer_multiple(&transfers) {
22+
let mut rx_buf1 = [0; 10];
23+
let tx_buf2 = [0x00, 0x01, 0x02, 0x03];
24+
let tx_buf3 = [0xff, 0xfe, 0xfd];
25+
let mut rx_buf3 = [0; 3];
26+
let result = {
27+
let mut transfers = vec![SpidevTransfer::read(&mut rx_buf1),
28+
SpidevTransfer::write(&tx_buf2),
29+
SpidevTransfer::read_write(&tx_buf3, &mut rx_buf3)];
30+
spidev.transfer_multiple(&mut transfers)
31+
};
32+
match result {
3933
Ok(_) => {
40-
for (i, transfer) in transfers.iter().enumerate() {
41-
println!("{}...", i);
42-
pprint_transfer(transfer);
43-
}
34+
println!("Read {:?}", rx_buf1);
35+
println!("Wrote {:?}", tx_buf2);
36+
println!("Wrote {:?} and read {:?}", tx_buf3, rx_buf3);
4437
}
4538
Err(err) => println!("{:?}", err),
4639
}

src/lib.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,13 @@
5151
//! fn full_duplex(spi: &mut Spidev) -> io::Result<()> {
5252
//! // "write" transfers are also reads at the same time with
5353
//! // the read having the same length as the write
54-
//! let mut transfer = SpidevTransfer::write(&[0x01, 0x02, 0x03]);
55-
//! try!(spi.transfer(&mut transfer));
56-
//! println!("{:?}", transfer.rx_buf);
54+
//! let tx_buf = [0x01, 0x02, 0x03];
55+
//! let mut rx_buf = [0; 3];
56+
//! {
57+
//! let mut transfer = SpidevTransfer::read_write(&tx_buf, &mut rx_buf);
58+
//! try!(spi.transfer(&mut transfer));
59+
//! }
60+
//! println!("{:?}", rx_buf);
5761
//! Ok(())
5862
//! }
5963
//!
@@ -247,9 +251,7 @@ impl Spidev {
247251
/// Chaining together multiple requests like this can reduce latency
248252
/// and be used for conveniently and efficient implementing some
249253
/// protocols without extra round trips back to userspace.
250-
pub fn transfer_multiple<'a, I>(&self, transfers: I) -> io::Result<()>
251-
where I: IntoIterator<Item = &'a SpidevTransfer>
252-
{
254+
pub fn transfer_multiple(&self, transfers: &mut [SpidevTransfer]) -> io::Result<()> {
253255
spidevioctl::transfer_multiple(self.devfile.as_raw_fd(), transfers)
254256
}
255257
}

src/spidevioctl.rs

Lines changed: 43 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#![allow(dead_code)]
1010

1111
use std::io;
12+
use std::marker::PhantomData;
1213
use std::mem;
1314
use std::os::unix::prelude::*;
1415
use super::SpiModeFlags;
@@ -64,19 +65,51 @@ fn from_nix_result<T>(res: ::nix::Result<T>) -> io::Result<T> {
6465
/// last transfer might write some register values.
6566
/// ```
6667
#[allow(non_camel_case_types)]
67-
#[derive(Debug)]
68+
#[derive(Debug, Default)]
6869
#[repr(C)]
69-
pub struct spi_ioc_transfer {
70-
pub tx_buf: u64,
71-
pub rx_buf: u64,
72-
pub len: u32,
70+
pub struct spi_ioc_transfer<'a, 'b> {
71+
tx_buf: u64,
72+
rx_buf: u64,
73+
len: u32,
7374

7475
// optional overrides
7576
pub speed_hz: u32,
7677
pub delay_usecs: u16,
7778
pub bits_per_word: u8,
7879
pub cs_change: u8,
7980
pub pad: u32,
81+
82+
tx_buf_ref: PhantomData<&'a [u8]>,
83+
rx_buf_ref: PhantomData<&'b mut [u8]>,
84+
}
85+
86+
impl<'a, 'b> spi_ioc_transfer<'a, 'b> {
87+
pub fn read(buff: &'b mut [u8]) -> Self {
88+
spi_ioc_transfer {
89+
rx_buf: buff.as_ptr() as *const () as usize as u64,
90+
len: buff.len() as u32,
91+
..Default::default()
92+
}
93+
}
94+
95+
pub fn write(buff: &'a [u8]) -> Self {
96+
spi_ioc_transfer {
97+
tx_buf: buff.as_ptr() as *const () as usize as u64,
98+
len: buff.len() as u32,
99+
..Default::default()
100+
}
101+
}
102+
103+
/// The `tx_buf` and `rx_buf` must be the same length.
104+
pub fn read_write(tx_buf: &'a [u8], rx_buf: &'b mut [u8]) -> Self {
105+
assert_eq!(tx_buf.len(), rx_buf.len());
106+
spi_ioc_transfer {
107+
rx_buf: rx_buf.as_ptr() as *const () as usize as u64,
108+
tx_buf: tx_buf.as_ptr() as *const () as usize as u64,
109+
len: tx_buf.len() as u32,
110+
..Default::default()
111+
}
112+
}
80113
}
81114

82115
mod ioctl {
@@ -114,64 +147,7 @@ mod ioctl {
114147

115148
/// Representation of a spidev transfer that is shared
116149
/// with external users
117-
#[derive(Default)]
118-
pub struct SpidevTransfer {
119-
pub tx_buf: Option<Box<[u8]>>,
120-
pub rx_buf: Option<Box<[u8]>>,
121-
len: u32,
122-
speed_hz: u32,
123-
delay_usecs: u16,
124-
bits_per_word: u8,
125-
cs_change: u8,
126-
pad: u32,
127-
}
128-
129-
impl SpidevTransfer {
130-
pub fn read(length: usize) -> SpidevTransfer {
131-
SpidevTransfer {
132-
tx_buf: None,
133-
rx_buf: Some(vec![0u8; length].into_boxed_slice()),
134-
len: length as u32,
135-
..Default::default()
136-
}
137-
}
138-
139-
pub fn write(tx_buf: &[u8]) -> SpidevTransfer {
140-
let len = tx_buf.len();
141-
let rx_buf_vec: Vec<u8> = vec![0; len];
142-
let mut tx_buf_vec = Vec::with_capacity(len);
143-
for i in 0..len {
144-
tx_buf_vec.push(tx_buf[i]);
145-
}
146-
147-
SpidevTransfer {
148-
tx_buf: Some(tx_buf_vec.into_boxed_slice()),
149-
rx_buf: Some(rx_buf_vec.into_boxed_slice()),
150-
len: tx_buf.len() as u32,
151-
..Default::default()
152-
}
153-
}
154-
155-
fn as_spi_ioc_transfer(&self) -> spi_ioc_transfer {
156-
spi_ioc_transfer {
157-
tx_buf: match self.tx_buf {
158-
Some(ref bufbox) => bufbox.as_ptr() as u64,
159-
None => 0,
160-
},
161-
rx_buf: match self.rx_buf {
162-
Some(ref bufbox) => bufbox.as_ptr() as u64,
163-
None => 0,
164-
},
165-
len: self.len,
166-
speed_hz: self.speed_hz,
167-
delay_usecs: self.delay_usecs,
168-
bits_per_word: self.bits_per_word,
169-
cs_change: self.cs_change,
170-
pad: self.pad,
171-
}
172-
}
173-
}
174-
150+
pub type SpidevTransfer<'a, 'b> = spi_ioc_transfer<'a, 'b>;
175151

176152
pub fn get_mode(fd: RawFd) -> io::Result<u8> {
177153
let mut mode: u8 = 0;
@@ -232,26 +208,17 @@ pub fn set_max_speed_hz(fd: RawFd, max_speed_hz: u32) -> io::Result<()> {
232208
}
233209

234210
pub fn transfer(fd: RawFd, transfer: &mut SpidevTransfer) -> io::Result<()> {
235-
let mut raw_transfer = transfer.as_spi_ioc_transfer();
236-
237211
// The kernel will directly modify the rx_buf of the SpidevTransfer
238212
// rx_buf if present, so there is no need to do any additional work
239-
try!(from_nix_result(unsafe { ioctl::spidev_transfer(fd, &mut raw_transfer) }));
213+
try!(from_nix_result(unsafe { ioctl::spidev_transfer(fd, transfer) }));
240214
Ok(())
241215
}
242216

243-
pub fn transfer_multiple<'a, I>(fd: RawFd, transfers: I) -> io::Result<()>
244-
where I: IntoIterator<Item = &'a SpidevTransfer>
245-
{
246-
// create a boxed slice containing several spi_ioc_transfers
247-
let mut raw_transfers = transfers.into_iter()
248-
.map(|transfer| transfer.as_spi_ioc_transfer())
249-
.collect::<Vec<_>>()
250-
.into_boxed_slice();
251-
let tot_size = raw_transfers.len() * mem::size_of::<spi_ioc_transfer>();
217+
pub fn transfer_multiple(fd: RawFd, transfers: &mut [SpidevTransfer]) -> io::Result<()> {
218+
let tot_size = transfers.len() * mem::size_of::<SpidevTransfer>();
252219

253220
try!(from_nix_result(unsafe {
254-
ioctl::spidev_transfer_buf(fd, raw_transfers.as_mut_ptr(), tot_size)
221+
ioctl::spidev_transfer_buf(fd, transfers.as_mut_ptr(), tot_size)
255222
}));
256223
Ok(())
257224
}

0 commit comments

Comments
 (0)