rpi_pal/i2c.rs
1//! Interface for the I2C peripheral.
2//!
3//! The Broadcom Serial Controller (BSC) peripheral controls a proprietary bus
4//! compliant with the I2C bus/interface. rpi-pal communicates with the BSC
5//! using the `i2cdev` device interface.
6//!
7//! ## I2C buses
8//!
9//! The Raspberry Pi 3 B+ and earlier models support three hardware I2C buses,
10//! however only the I2C bus on physical pins 3 and 5 should be used to communicate
11//! with slave devices. The other two buses are used internally as an HDMI
12//! interface, and for HAT identification.
13//!
14//! On the Raspberry Pi 4 B, 400 and 5, three additional I2C buses are available,
15//! depending on your configuration, as explained below.
16//!
17//! ### I2C0 / I2C1
18//!
19//! On the Raspberry Pi B Rev 1, physical pins 3 (SDA) and 5 (SCL) are tied to I2C0.
20//! On every other Raspberry Pi model, they're connected to I2C1.
21//!
22//! The I2C bus connected to these pins is disabled by
23//! default. You can enable it through `sudo raspi-config`, or by manually
24//! adding `dtparam=i2c_arm=on` to `/boot/firmware/config.txt`. Remember to reboot
25//! the Raspberry Pi afterwards.
26//!
27//! * SDA: BCM GPIO 2 (physical pin 3)
28//! * SCL: BCM GPIO 3 (physical pin 5)
29//!
30//! ### I2C3
31//!
32//! I2C3 can be enabled by adding `dtoverlay=i2c3` to `/boot/firmware/config.txt`.
33//!
34//! * SDA: BCM GPIO 4 (physical pin 7)
35//! * SCL: BCM GPIO 5 (physical pin 29)
36//!
37//! ### I2C4
38//!
39//! I2C4 can be enabled by adding `dtoverlay=i2c4` to `/boot/firmware/config.txt`.
40//!
41//! * SDA: BCM GPIO 8 (physical pin 24)
42//! * SCL: BCM GPIO 9 (physical pin 21)
43//!
44//! ### I2C5
45//!
46//! I2C5 can be enabled by adding `dtoverlay=i2c5` to `/boot/firmware/config.txt`.
47//!
48//! * SDA: BCM GPIO 12 (physical pin 32)
49//! * SCL: BCM GPIO 13 (physical pin 33)
50//!
51//! ### I2C6
52//!
53//! I2C6 can be enabled by adding `dtoverlay=i2c6` to `/boot/firmware/config.txt`.
54//!
55//! * SDA: BCM GPIO 22 (physical pin 15)
56//! * SCL: BCM GPIO 23 (physical pin 16)
57//!
58//! ### Alternative pins
59//!
60//! The GPIO pin numbers mentioned above are part of the default configuration.
61//! Some of their functionality can be moved to different pins. Read
62//! `/boot/overlays/README` for more information.
63//!
64//! ### Software I2C
65//!
66//! In addition to the hardware I2C buses, it's possible to configure a
67//! bit-banged software I2C bus on any available GPIO pins through the `i2c-gpio`
68//! device tree overlay. More details on enabling and configuring `i2c-gpio`
69//! can be found in `/boot/overlays/README`.
70//!
71//! ## Transmission speed
72//!
73//! The BSC supports I2C data transfer rates up to 400 kbit/s (Fast-mode).
74//!
75//! By default, the I2C bus clock speed is set to 100 kHz. Transferring
76//! 1 bit takes 1 clock cycle. You can change the
77//! transfer rate by adding `dtparam=i2c_arm_baudrate=X` to
78//! `/boot/firmware/config.txt`, where `X` should be replaced with the
79//! clock frequency in hertz (Hz). Remember to reboot
80//! the Raspberry Pi afterwards.
81//!
82//! ## Not supported
83//!
84//! Some I2C and SMBus features aren't fully supported by the `i2cdev` interface, the underlying driver or
85//! the BCM283x SoC: 10-bit slave addresses, SMBus Block Read, SMBus Block Process Call, SMBus Host Notify,
86//! SMBus Read/Write 32/64, and the SMBus Address Resolution Protocol.
87//!
88//! While clock stretching is supported, a bug exists in the implementation on the BCM283x SoC that will result
89//! in corrupted data when a slave device uses clock stretching at arbitrary points during the transfer.
90//! Clock stretching only works properly during read operations, directly after the ACK phase, when the additional
91//! delay is longer than half of a clock period. More information can be found [here](https://elinux.org/BCM2835_datasheet_errata#p35_I2C_clock_stretching).
92//!
93//! A possible workaround for slave devices that require clock stretching at other points during the transfer is
94//! to use a bit-banged software I2C bus by configuring the `i2c-gpio` device tree overlay as described in `/boot/overlays/README`.
95//!
96//! ## Troubleshooting
97//!
98//! ### Permission denied
99//!
100//! If [`new`] or [`with_bus`] returns an `io::ErrorKind::PermissionDenied`
101//! error, make sure the file permissions for `/dev/i2c-1` or `/dev/i2c-0`
102//! are correct, and the current user is a member of the `i2c` group.
103//!
104//! ### Timed out
105//!
106//! Transactions return an `io::ErrorKind::TimedOut` error when their duration
107//! exceeds the timeout value. You can change the timeout using [`set_timeout`].
108//!
109//! [`new`]: struct.I2c.html#method.new
110//! [`with_bus`]: struct.I2c.html#method.with_bus
111//! [`set_timeout`]: struct.I2c.html#method.set_timeout
112
113#![allow(dead_code)]
114
115use std::error;
116use std::fmt;
117use std::fs::{File, OpenOptions};
118use std::io;
119use std::io::{Read, Write};
120use std::marker::PhantomData;
121use std::os::unix::io::AsRawFd;
122use std::result;
123
124use libc::c_ulong;
125
126use crate::system;
127use crate::system::{DeviceInfo, Model};
128
129#[cfg(any(
130 feature = "embedded-hal-0",
131 feature = "embedded-hal",
132 feature = "embedded-hal-nb"
133))]
134mod hal;
135mod ioctl;
136
137pub use self::ioctl::Capabilities;
138
139/// Errors that can occur when accessing the I2C peripheral.
140#[derive(Debug)]
141pub enum Error {
142 /// I/O error.
143 Io(io::Error),
144 /// Invalid slave address.
145 ///
146 /// I2C supports 7-bit and 10-bit addresses. Several 7-bit addresses
147 /// can't be used as slave addresses.
148 InvalidSlaveAddress(u16),
149 /// I2C/SMBus feature not supported.
150 ///
151 /// The underlying drivers don't support the selected I2C feature or SMBus protocol.
152 FeatureNotSupported,
153 /// Unknown model.
154 ///
155 /// The Raspberry Pi model or SoC can't be identified. Support for
156 /// new models is usually added shortly after they are officially
157 /// announced and available to the public. Make sure you're using
158 /// the latest release of rpi-pal.
159 ///
160 /// You may also encounter this error if your Linux distribution
161 /// doesn't provide any of the common user-accessible system files
162 /// that are used to identify the model and SoC.
163 UnknownModel,
164}
165
166impl fmt::Display for Error {
167 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168 match *self {
169 Error::Io(ref err) => write!(f, "I/O error: {}", err),
170 Error::InvalidSlaveAddress(address) => write!(f, "Invalid slave address: {}", address),
171 Error::FeatureNotSupported => write!(f, "I2C/SMBus feature not supported"),
172 Error::UnknownModel => write!(f, "Unknown Raspberry Pi model"),
173 }
174 }
175}
176
177impl error::Error for Error {}
178
179impl From<io::Error> for Error {
180 fn from(err: io::Error) -> Error {
181 Error::Io(err)
182 }
183}
184
185impl From<system::Error> for Error {
186 fn from(_err: system::Error) -> Error {
187 Error::UnknownModel
188 }
189}
190
191/// Result type returned from methods that can have `i2c::Error`s.
192pub type Result<T> = result::Result<T, Error>;
193
194/// Provides access to the Raspberry Pi's I2C peripheral.
195///
196/// Before using `I2c`, make sure your Raspberry Pi has the necessary I2C buses
197/// enabled. More information can be found [here].
198///
199/// Besides basic I2C communication through buffer reads and writes, `I2c` can
200/// also be used with devices that require SMBus (System Management Bus) support.
201/// SMBus is based on I2C, and defines more structured message transactions
202/// through its various protocols. More details can be found in the latest SMBus
203/// [specification].
204///
205/// The `embedded-hal` trait implementations for `I2c` can be enabled by specifying
206/// the optional `hal` feature in the dependency declaration for the `rpi_pal` crate.
207///
208/// [here]: index.html#i2c-buses
209/// [specification]: http://smbus.org/specs/SMBus_3_1_20180319.pdf
210#[derive(Debug)]
211pub struct I2c {
212 bus: u8,
213 funcs: Capabilities,
214 i2cdev: File,
215 addr_10bit: bool,
216 address: u16,
217 // The not_sync field is a workaround to force !Sync. I2c isn't safe for
218 // Sync because of ioctl() and the underlying drivers. This avoids needing
219 // #![feature(optin_builtin_traits)] to manually add impl !Sync for I2c.
220 not_sync: PhantomData<*const ()>,
221}
222
223impl I2c {
224 /// Constructs a new `I2c`.
225 ///
226 /// `new` attempts to identify which I2C bus is bound to physical pins 3 (SDA)
227 /// and 5 (SCL) based on the Raspberry Pi model.
228 ///
229 /// More information on configuring the I2C buses can be found [here].
230 ///
231 /// [here]: index.html#i2c-buses
232 pub fn new() -> Result<I2c> {
233 match DeviceInfo::new()?.model() {
234 // Pi B Rev 1 uses I2C0
235 Model::RaspberryPiBRev1 => I2c::with_bus(0),
236 _ => {
237 // Pi 4B or later could have I2C3 enabled on pins 3 and 5
238 I2c::with_bus(1).or_else(|_| I2c::with_bus(3))
239 }
240 }
241 }
242
243 /// Constructs a new `I2c` using the specified bus.
244 ///
245 /// `bus` indicates the selected I2C bus. You'll typically want to select the
246 /// bus that's bound to physical pins 3 (SDA) and 5 (SCL). On the Raspberry
247 /// Pi B Rev 1, those pins are tied to bus 0. On every other Raspberry
248 /// Pi model, they're connected to bus 1. Additional I2C buses are available
249 /// on the Raspberry Pi 4 B, 400 and 5.
250 ///
251 /// More information on configuring the I2C buses can be found [here].
252 ///
253 /// [here]: index.html#i2c-buses
254 pub fn with_bus(bus: u8) -> Result<I2c> {
255 // bus is a u8, because any 8-bit bus ID could potentially
256 // be configured for bit banging I2C using i2c-gpio.
257 let i2cdev = OpenOptions::new()
258 .read(true)
259 .write(true)
260 .open(format!("/dev/i2c-{}", bus))?;
261
262 let capabilities = ioctl::funcs(i2cdev.as_raw_fd())?;
263
264 // Disable 10-bit addressing if it's supported
265 if capabilities.addr_10bit() {
266 ioctl::set_addr_10bit(i2cdev.as_raw_fd(), 0)?;
267 }
268
269 // Disable PEC if it's supported
270 if capabilities.smbus_pec() {
271 ioctl::set_pec(i2cdev.as_raw_fd(), 0)?;
272 }
273
274 Ok(I2c {
275 bus,
276 funcs: capabilities,
277 i2cdev,
278 addr_10bit: false,
279 address: 0,
280 not_sync: PhantomData,
281 })
282 }
283
284 /// Returns information on the functionality supported by the underlying drivers.
285 ///
286 /// The returned [`Capabilities`] instance lists the available
287 /// I2C and SMBus features.
288 ///
289 /// [`Capabilities`]: struct.Capabilities.html
290 pub fn capabilities(&self) -> Capabilities {
291 self.funcs
292 }
293
294 /// Returns the I2C bus ID.
295 pub fn bus(&self) -> u8 {
296 self.bus
297 }
298
299 /// Returns the clock frequency in hertz (Hz).
300 pub fn clock_speed(&self) -> Result<u32> {
301 let mut buffer = [0u8; 4];
302
303 File::open(format!(
304 "/sys/class/i2c-adapter/i2c-{}/of_node/clock-frequency",
305 self.bus
306 ))?
307 .read_exact(&mut buffer)?;
308
309 Ok(u32::from(buffer[3])
310 | (u32::from(buffer[2]) << 8)
311 | (u32::from(buffer[1]) << 16)
312 | (u32::from(buffer[0]) << 24))
313 }
314
315 /// Sets a 7-bit or 10-bit slave address.
316 ///
317 /// `slave_address` refers to the slave device you're communicating with.
318 /// The specified address shouldn't include the R/W bit.
319 ///
320 /// By default, 10-bit addressing is disabled, which means
321 /// `set_slave_address` only accepts 7-bit addresses. 10-bit addressing
322 /// can be enabled with [`set_addr_10bit`]. Note that setting a 7-bit
323 /// address when 10-bit addressing is enabled won't correctly target a
324 /// slave device that doesn't support 10-bit addresses.
325 ///
326 /// [`set_addr_10bit`]: #method.set_addr_10bit
327 pub fn set_slave_address(&mut self, slave_address: u16) -> Result<()> {
328 // Filter out invalid and unsupported addresses
329 if (!self.addr_10bit && ((slave_address >> 3) == 0b1111 || slave_address > 0x7F))
330 || (self.addr_10bit && slave_address > 0x03FF)
331 {
332 return Err(Error::InvalidSlaveAddress(slave_address));
333 }
334
335 ioctl::set_slave_address(self.i2cdev.as_raw_fd(), c_ulong::from(slave_address))?;
336
337 self.address = slave_address;
338
339 Ok(())
340 }
341
342 /// Sets the maximum duration of a transaction in milliseconds (ms).
343 ///
344 /// Transactions that take longer than `timeout` return an
345 /// `io::ErrorKind::TimedOut` error.
346 ///
347 /// `timeout` has a resolution of 10ms.
348 pub fn set_timeout(&self, timeout: u32) -> Result<()> {
349 // Contrary to the i2cdev documentation, this seems to
350 // be used as a timeout for (part of?) the I2C transaction.
351 ioctl::set_timeout(self.i2cdev.as_raw_fd(), timeout as c_ulong)?;
352
353 Ok(())
354 }
355
356 fn set_retries(&self, retries: u32) -> Result<()> {
357 // Set to private. While i2cdev implements retries, the underlying drivers don't.
358 ioctl::set_retries(self.i2cdev.as_raw_fd(), retries as c_ulong)?;
359
360 Ok(())
361 }
362
363 /// Enables or disables 10-bit addressing.
364 ///
365 /// 10-bit addressing currently isn't supported on the Raspberry Pi. `set_addr_10bit` returns
366 /// `Err(`[`Error::FeatureNotSupported`]`)` unless underlying driver support is detected.
367 ///
368 /// By default, `addr_10bit` is set to `false`.
369 ///
370 /// [`Error::FeatureNotSupported`]: enum.Error.html#variant.FeatureNotSupported
371 pub fn set_addr_10bit(&mut self, addr_10bit: bool) -> Result<()> {
372 if !self.capabilities().addr_10bit() {
373 return Err(Error::FeatureNotSupported);
374 }
375
376 ioctl::set_addr_10bit(self.i2cdev.as_raw_fd(), addr_10bit as c_ulong)?;
377
378 self.addr_10bit = addr_10bit;
379
380 Ok(())
381 }
382
383 /// Receives incoming data from the slave device and writes it to `buffer`.
384 ///
385 /// `read` reads as many bytes as can fit in `buffer`.
386 ///
387 /// Sequence: START → Address + Read Bit → Incoming Bytes → STOP
388 ///
389 /// Returns how many bytes were read.
390 pub fn read(&mut self, buffer: &mut [u8]) -> Result<usize> {
391 Ok(self.i2cdev.read(buffer)?)
392 }
393
394 /// Sends the outgoing data contained in `buffer` to the slave device.
395 ///
396 /// Sequence: START → Address + Write Bit → Outgoing Bytes → STOP
397 ///
398 /// Returns how many bytes were written.
399 pub fn write(&mut self, buffer: &[u8]) -> Result<usize> {
400 Ok(self.i2cdev.write(buffer)?)
401 }
402
403 /// Sends the outgoing data contained in `write_buffer` to the slave device, and
404 /// then fills `read_buffer` with incoming data.
405 ///
406 /// Compared to calling [`write`] and [`read`] separately, `write_read` doesn't
407 /// issue a STOP condition in between the write and read operation. A repeated
408 /// START is sent instead.
409 ///
410 /// `write_read` reads as many bytes as can fit in `read_buffer`. The maximum
411 /// number of bytes in either `write_buffer` or `read_buffer` can't exceed 8192.
412 ///
413 /// Sequence: START → Address + Write Bit → Outgoing Bytes → Repeated START →
414 /// Address + Read Bit → Incoming Bytes → STOP
415 ///
416 /// [`write`]: #method.write
417 /// [`read`]: #method.read
418 pub fn write_read(&self, write_buffer: &[u8], read_buffer: &mut [u8]) -> Result<()> {
419 ioctl::i2c_write_read(
420 self.i2cdev.as_raw_fd(),
421 self.address,
422 self.addr_10bit,
423 write_buffer,
424 read_buffer,
425 )?;
426
427 Ok(())
428 }
429
430 /// Sends an 8-bit `command`, and then fills a multi-byte `buffer` with
431 /// incoming data.
432 ///
433 /// `block_read` can read a maximum of 32 bytes.
434 ///
435 /// Although `block_read` isn't part of the SMBus protocol, it uses the
436 /// SMBus functionality to offer this commonly used I2C transaction format.
437 /// The difference between `block_read` and [`smbus_block_read`] is that the
438 /// latter also expects a byte count from the slave device.
439 ///
440 /// Sequence: START → Address + Write Bit → Command → Repeated START
441 /// → Address + Read Bit → Incoming Bytes → STOP
442 ///
443 /// [`smbus_block_read`]: #method.smbus_block_read
444 pub fn block_read(&self, command: u8, buffer: &mut [u8]) -> Result<()> {
445 ioctl::i2c_block_read(self.i2cdev.as_raw_fd(), command, buffer)?;
446
447 Ok(())
448 }
449
450 /// Sends an 8-bit `command` followed by a multi-byte `buffer`.
451 ///
452 /// `block_write` can write a maximum of 32 bytes. Any additional data contained
453 /// in `buffer` is ignored.
454 ///
455 /// Although `block_write` isn't part of the SMBus protocol, it uses the
456 /// SMBus functionality to offer this commonly used I2C transaction format. The
457 /// difference between `block_write` and [`smbus_block_write`] is that the latter
458 /// also sends a byte count to the slave device.
459 ///
460 /// Sequence: START → Address + Write Bit → Command → Outgoing Bytes → STOP
461 ///
462 /// [`smbus_block_write`]: #method.smbus_block_write
463 pub fn block_write(&self, command: u8, buffer: &[u8]) -> Result<()> {
464 ioctl::i2c_block_write(self.i2cdev.as_raw_fd(), command, buffer)?;
465
466 Ok(())
467 }
468
469 // Note: smbus_read/write_32/64 could theoretically be emulated using block_read/write
470 // provided the PEC value is calculated in software
471
472 /// Sends a 1-bit `command` in place of the R/W bit.
473 ///
474 /// Sequence: START → Address + Command Bit → STOP
475 pub fn smbus_quick_command(&self, command: bool) -> Result<()> {
476 ioctl::smbus_quick_command(self.i2cdev.as_raw_fd(), command)?;
477
478 Ok(())
479 }
480
481 /// Receives an 8-bit value.
482 ///
483 /// Sequence: START → Address + Read Bit → Incoming Byte → STOP
484 pub fn smbus_receive_byte(&self) -> Result<u8> {
485 Ok(ioctl::smbus_receive_byte(self.i2cdev.as_raw_fd())?)
486 }
487
488 /// Sends an 8-bit `value`.
489 ///
490 /// Sequence: START → Address + Write Bit → Outgoing Byte → STOP
491 pub fn smbus_send_byte(&self, value: u8) -> Result<()> {
492 ioctl::smbus_send_byte(self.i2cdev.as_raw_fd(), value)?;
493
494 Ok(())
495 }
496
497 /// Sends an 8-bit `command`, and receives an 8-bit value.
498 ///
499 /// Sequence: START → Address + Write Bit → Command → Repeated START
500 /// → Address + Read Bit → Incoming Byte → STOP
501 pub fn smbus_read_byte(&self, command: u8) -> Result<u8> {
502 Ok(ioctl::smbus_read_byte(self.i2cdev.as_raw_fd(), command)?)
503 }
504
505 /// Sends an 8-bit `command` and an 8-bit `value`.
506 ///
507 /// Sequence: START → Address + Write Bit → Command → Outgoing Byte → STOP
508 pub fn smbus_write_byte(&self, command: u8, value: u8) -> Result<()> {
509 ioctl::smbus_write_byte(self.i2cdev.as_raw_fd(), command, value)?;
510
511 Ok(())
512 }
513
514 /// Sends an 8-bit `command`, and receives a 16-bit value.
515 ///
516 /// Based on the SMBus protocol definition, the first byte received is
517 /// stored as the low byte of the 16-bit value, and the second byte as
518 /// the high byte. Some devices may require you to swap these bytes. In those
519 /// cases you can use the convenience method [`smbus_read_word_swapped`] instead.
520 ///
521 /// Sequence: START → Address + Write Bit → Command → Repeated START
522 /// → Address + Read Bit → Incoming Byte Low → Incoming Byte High → STOP
523 ///
524 /// [`smbus_read_word_swapped`]: #method.smbus_read_word_swapped
525 pub fn smbus_read_word(&self, command: u8) -> Result<u16> {
526 Ok(ioctl::smbus_read_word(self.i2cdev.as_raw_fd(), command)?)
527 }
528
529 /// Sends an 8-bit `command`, and receives a 16-bit `value` in a non-standard swapped byte order.
530 ///
531 /// `smbus_read_word_swapped` is a convenience method that works similarly to [`smbus_read_word`],
532 /// but reverses the byte order of the incoming 16-bit value. The high byte is received first,
533 /// and the low byte second.
534 ///
535 /// Sequence: START → Address + Write Bit → Command → Repeated START
536 /// → Address + Read Bit → Incoming Byte High → Incoming Byte Low → STOP
537 ///
538 /// [`smbus_read_word`]: #method.smbus_read_word
539 pub fn smbus_read_word_swapped(&self, command: u8) -> Result<u16> {
540 let value = ioctl::smbus_read_word(self.i2cdev.as_raw_fd(), command)?;
541
542 Ok(((value & 0xFF00) >> 8) | ((value & 0xFF) << 8))
543 }
544
545 /// Sends an 8-bit `command` and a 16-bit `value`.
546 ///
547 /// Based on the SMBus protocol definition, the first byte sent is the low byte
548 /// of the 16-bit value, and the second byte is the high byte. Some devices may
549 /// require you to swap these bytes. In those cases you can use the convenience method
550 /// [`smbus_write_word_swapped`] instead.
551 ///
552 /// Sequence: START → Address + Write Bit → Command → Outgoing Byte Low → Outgoing Byte High → STOP
553 ///
554 /// [`smbus_write_word_swapped`]: #method.smbus_write_word_swapped
555 pub fn smbus_write_word(&self, command: u8, value: u16) -> Result<()> {
556 ioctl::smbus_write_word(self.i2cdev.as_raw_fd(), command, value)?;
557
558 Ok(())
559 }
560
561 /// Sends an 8-bit `command` and a 16-bit `value` in a non-standard swapped byte order.
562 ///
563 /// `smbus_write_word_swapped` is a convenience method that works similarly to [`smbus_write_word`], but reverses the byte
564 /// order of the outgoing 16-bit value. The high byte is sent first, and the low byte second.
565 ///
566 /// Sequence: START → Address + Write Bit → Command → Outgoing Byte High → Outgoing Byte Low → STOP
567 ///
568 /// [`smbus_write_word`]: #method.smbus_write_word
569 pub fn smbus_write_word_swapped(&self, command: u8, value: u16) -> Result<()> {
570 ioctl::smbus_write_word(
571 self.i2cdev.as_raw_fd(),
572 command,
573 ((value & 0xFF00) >> 8) | ((value & 0xFF) << 8),
574 )?;
575
576 Ok(())
577 }
578
579 /// Sends an 8-bit `command` and a 16-bit `value`, and then receives a 16-bit value in response.
580 ///
581 /// Based on the SMBus protocol definition, for both the outgoing and incoming 16-bit value,
582 /// the first byte transferred is the low byte of the 16-bit value, and the second byte is the
583 /// high byte. Some devices may require you to swap these bytes. In those cases you can use the
584 /// convenience method [`smbus_process_call_swapped`] instead.
585 ///
586 /// Sequence: START → Address + Write Bit → Command → Outgoing Byte Low →
587 /// Outgoing Byte High → Repeated START → Address + Read Bit → Incoming Byte Low →
588 /// Incoming Byte High → STOP
589 ///
590 /// [`smbus_process_call_swapped`]: #method.smbus_process_call_swapped
591 pub fn smbus_process_call(&self, command: u8, value: u16) -> Result<u16> {
592 Ok(ioctl::smbus_process_call(
593 self.i2cdev.as_raw_fd(),
594 command,
595 value,
596 )?)
597 }
598
599 /// Sends an 8-bit `command` and a 16-bit `value`, and then receives a 16-bit value in response, in
600 /// a non-standard byte order.
601 ///
602 /// `smbus_process_call_swapped` is a convenience method that works similarly to [`smbus_process_call`],
603 /// but reverses the byte order of the outgoing and incoming 16-bit value. The high byte is transferred
604 /// first, and the low byte second.
605 ///
606 /// Sequence: START → Address + Write Bit → Command → Outgoing Byte High →
607 /// Outgoing Byte Low → Repeated START → Address + Read Bit → Incoming Byte High →
608 /// Incoming Byte Low → STOP
609 ///
610 /// [`smbus_process_call`]: #method.smbus_process_call
611 pub fn smbus_process_call_swapped(&self, command: u8, value: u16) -> Result<u16> {
612 let response = ioctl::smbus_process_call(
613 self.i2cdev.as_raw_fd(),
614 command,
615 ((value & 0xFF00) >> 8) | ((value & 0xFF) << 8),
616 )?;
617
618 Ok(((response & 0xFF00) >> 8) | ((response & 0xFF) << 8))
619 }
620
621 /// Sends an 8-bit `command`, and then receives an 8-bit byte count along with a
622 /// multi-byte `buffer`.
623 ///
624 /// `smbus_block_read` currently isn't supported on the Raspberry Pi, and returns
625 /// `Err(`[`Error::FeatureNotSupported`]`)` unless underlying driver support is
626 /// detected. You might be able to emulate the `smbus_block_read` functionality
627 /// with [`write_read`], [`block_read`] or [`read`] provided the length of the
628 /// expected incoming data is known beforehand, or the slave device allows the
629 /// master to read more data than it needs to send.
630 ///
631 /// `smbus_block_read` can read a maximum of 32 bytes.
632 ///
633 /// Sequence: START → Address + Write Bit → Command → Repeated START →
634 /// Address + Read Bit → Incoming Byte Count → Incoming Bytes → STOP
635 ///
636 /// Returns how many bytes were read.
637 ///
638 /// [`Error::FeatureNotSupported`]: enum.Error.html#variant.FeatureNotSupported
639 /// [`write_read`]: #method.write_read
640 /// [`block_read`]: #method.block_read
641 /// [`read`]: #method.read
642 pub fn smbus_block_read(&self, command: u8, buffer: &mut [u8]) -> Result<usize> {
643 if !self.capabilities().smbus_block_read() {
644 return Err(Error::FeatureNotSupported);
645 }
646
647 Ok(ioctl::smbus_block_read(
648 self.i2cdev.as_raw_fd(),
649 command,
650 buffer,
651 )?)
652 }
653
654 /// Sends an 8-bit `command` and an 8-bit byte count along with a multi-byte `buffer`.
655 ///
656 /// `smbus_block_write` can write a maximum of 32 bytes. Any additional data contained
657 /// in `buffer` is ignored.
658 ///
659 /// Sequence: START → Address + Write Bit → Command → Outgoing Byte Count
660 /// → Outgoing Bytes → STOP
661 pub fn smbus_block_write(&self, command: u8, buffer: &[u8]) -> Result<()> {
662 ioctl::smbus_block_write(self.i2cdev.as_raw_fd(), command, buffer)?;
663
664 Ok(())
665 }
666
667 /// Enables or disables SMBus Packet Error Checking.
668 ///
669 /// Packet Error Checking inserts a CRC-8 Packet Error Code (PEC) byte before each STOP
670 /// condition for all SMBus protocols, except Quick Command and Host Notify.
671 ///
672 /// The PEC is calculated on all message bytes except the START, STOP, ACK and NACK bits.
673 ///
674 /// By default, `pec` is set to `false`.
675 pub fn set_smbus_pec(&self, pec: bool) -> Result<()> {
676 ioctl::set_pec(self.i2cdev.as_raw_fd(), pec as c_ulong)?;
677
678 Ok(())
679 }
680}
681
682// Send is safe for I2c, but we're marked !Send because of the dummy pointer that's
683// needed to force !Sync.
684unsafe impl Send for I2c {}