|
9 | 9 | #![allow(dead_code)]
|
10 | 10 |
|
11 | 11 | use std::io;
|
| 12 | +use std::marker::PhantomData; |
12 | 13 | use std::mem;
|
13 | 14 | use std::os::unix::prelude::*;
|
14 | 15 | use super::SpiModeFlags;
|
@@ -64,19 +65,51 @@ fn from_nix_result<T>(res: ::nix::Result<T>) -> io::Result<T> {
|
64 | 65 | /// last transfer might write some register values.
|
65 | 66 | /// ```
|
66 | 67 | #[allow(non_camel_case_types)]
|
67 |
| -#[derive(Debug)] |
| 68 | +#[derive(Debug, Default)] |
68 | 69 | #[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, |
73 | 74 |
|
74 | 75 | // optional overrides
|
75 | 76 | pub speed_hz: u32,
|
76 | 77 | pub delay_usecs: u16,
|
77 | 78 | pub bits_per_word: u8,
|
78 | 79 | pub cs_change: u8,
|
79 | 80 | 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 | + } |
80 | 113 | }
|
81 | 114 |
|
82 | 115 | mod ioctl {
|
@@ -114,64 +147,7 @@ mod ioctl {
|
114 | 147 |
|
115 | 148 | /// Representation of a spidev transfer that is shared
|
116 | 149 | /// 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>; |
175 | 151 |
|
176 | 152 | pub fn get_mode(fd: RawFd) -> io::Result<u8> {
|
177 | 153 | let mut mode: u8 = 0;
|
@@ -232,26 +208,17 @@ pub fn set_max_speed_hz(fd: RawFd, max_speed_hz: u32) -> io::Result<()> {
|
232 | 208 | }
|
233 | 209 |
|
234 | 210 | pub fn transfer(fd: RawFd, transfer: &mut SpidevTransfer) -> io::Result<()> {
|
235 |
| - let mut raw_transfer = transfer.as_spi_ioc_transfer(); |
236 |
| - |
237 | 211 | // The kernel will directly modify the rx_buf of the SpidevTransfer
|
238 | 212 | // 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) })); |
240 | 214 | Ok(())
|
241 | 215 | }
|
242 | 216 |
|
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>(); |
252 | 219 |
|
253 | 220 | 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) |
255 | 222 | }));
|
256 | 223 | Ok(())
|
257 | 224 | }
|
0 commit comments