1#![deny(missing_docs)]
2#![doc(html_root_url = "https://docs.rs/ddc-i2c/0.2.2/")]
3
4extern crate ddc;
24extern crate i2c;
25#[cfg(all(target_os = "linux", feature = "i2c-linux"))]
26extern crate i2c_linux;
27extern crate resize_slice;
28
29use {
30 ddc::{DdcCommand, DdcCommandMarker, DdcCommandRaw, DdcCommandRawMarker, DdcHost, Delay, Eddc, Edid, ErrorCode},
31 resize_slice::ResizeSlice,
32 std::{cmp, error, fmt, io, iter, thread::sleep, time::Duration},
33};
34
35#[cfg(all(target_os = "linux", feature = "with-linux-enumerate"))]
36mod enumerate;
37#[cfg(all(target_os = "linux", feature = "with-linux-enumerate"))]
38pub use enumerate::Enumerator as I2cDeviceEnumerator;
39
40#[derive(Clone, Debug)]
42pub struct I2cDdc<I> {
43 inner: I,
44 delay: Delay,
45}
46
47#[cfg(all(target_os = "linux", feature = "i2c-linux"))]
49pub type I2cDeviceDdc = I2cDdc<::i2c_linux::I2c<::std::fs::File>>;
50
51#[cfg(all(target_os = "linux", feature = "i2c-linux"))]
53pub fn from_i2c_device<P: AsRef<::std::path::Path>>(p: P) -> ::std::io::Result<I2cDeviceDdc> {
54 Ok(I2cDdc::new(::i2c_linux::I2c::from_path(p)?))
55}
56
57impl<I> I2cDdc<I> {
58 pub fn new(i2c: I) -> Self {
60 I2cDdc {
61 inner: i2c,
62 delay: Default::default(),
63 }
64 }
65
66 pub fn into_inner(self) -> I {
68 self.inner
69 }
70
71 pub fn inner_ref(&self) -> &I {
73 &self.inner
74 }
75
76 pub fn inner_mut(&mut self) -> &mut I {
78 &mut self.inner
79 }
80}
81
82impl<I: i2c::Address + i2c::BlockTransfer> Edid for I2cDdc<I> {
84 type EdidError = I::Error;
85
86 fn read_edid(&mut self, mut offset: u8, mut data: &mut [u8]) -> Result<usize, I::Error> {
87 self.inner.set_slave_address(ddc::I2C_ADDRESS_EDID, false)?;
88
89 let mut len = 0;
90 while !data.is_empty() {
91 let datalen = cmp::min(0x80, data.len());
92 let read = self.inner.i2c_read_block_data(offset, &mut data[..datalen])?;
93 if read == 0 {
94 break
95 }
96 len += read;
97 offset = if let Some(offset) = offset.checked_add(read as u8) {
98 offset
99 } else {
100 break
101 };
102 data.resize_from(read);
103 }
104
105 Ok(len)
106 }
107}
108
109impl<I: i2c::Address + i2c::BlockTransfer + i2c::BulkTransfer> Eddc for I2cDdc<I> {
112 fn read_eddc_edid(&mut self, segment: u8, offset: u8, data: &mut [u8]) -> Result<usize, I::Error> {
113 let len = {
114 let mut msgs = [
115 i2c::Message::Write {
116 address: ddc::I2C_ADDRESS_EDID_SEGMENT,
117 data: &[segment],
118 flags: Default::default(),
119 },
120 i2c::Message::Write {
121 address: ddc::I2C_ADDRESS_EDID,
122 data: &[offset],
123 flags: Default::default(),
124 },
125 i2c::Message::Read {
126 address: ddc::I2C_ADDRESS_EDID,
127 data,
128 flags: Default::default(),
129 },
130 ];
131 self.inner.i2c_transfer(&mut msgs)?;
132 msgs[2].len()
133 };
134
135 Ok(len)
136 }
137}
138
139impl<I: i2c::Master> ::DdcHost for I2cDdc<I> {
140 type Error = Error<I::Error>;
141
142 fn sleep(&mut self) {
143 self.delay.sleep()
144 }
145}
146
147impl<I: i2c::Address + i2c::ReadWrite> DdcCommandRaw for I2cDdc<I> {
148 fn execute_raw<'a>(
149 &mut self,
150 data: &[u8],
151 out: &'a mut [u8],
152 response_delay: Duration,
153 ) -> Result<&'a mut [u8], Error<I::Error>> {
154 assert!(data.len() <= 36);
155
156 let mut packet = [0u8; 36 + 3];
157 let packet = Self::encode_command(data, &mut packet);
158 self.inner
159 .set_slave_address(ddc::I2C_ADDRESS_DDC_CI, false)
160 .map_err(Error::I2c)?;
161
162 let full_len = {
163 self.sleep();
164 self.inner.i2c_write(packet).map_err(Error::I2c)?;
165 if !out.is_empty() {
166 sleep(response_delay);
167 self.inner.i2c_read(out).map_err(Error::I2c)?
168 } else {
169 return Ok(out)
170 }
171 };
172
173 if full_len < 2 {
174 return Err(Error::Ddc(ErrorCode::InvalidLength))
175 }
176
177 let len = (out[1] & 0x7f) as usize;
178
179 if out[1] & 0x80 == 0 {
180 return Err(Error::Ddc(ErrorCode::Invalid("Expected DDC/CI length bit".into())))
182 }
183
184 if full_len < len + 2 {
185 return Err(Error::Ddc(ErrorCode::InvalidLength))
186 }
187
188 let checksum = Self::checksum(
189 iter::once(((ddc::I2C_ADDRESS_DDC_CI as u8) << 1) | 1)
190 .chain(iter::once(ddc::SUB_ADDRESS_DDC_CI))
191 .chain(out[1..2 + len].iter().cloned()),
192 );
193
194 if out[2 + len] != checksum {
195 return Err(Error::Ddc(ErrorCode::InvalidChecksum))
196 }
197
198 Ok(&mut out[2..2 + len])
199 }
200}
201
202impl<I: i2c::Address + i2c::ReadWrite> DdcCommandMarker for I2cDdc<I> {}
203
204impl<I: i2c::Address + i2c::ReadWrite> DdcCommandRawMarker for I2cDdc<I> {
205 fn set_sleep_delay(&mut self, delay: Delay) {
206 self.delay = delay;
207 }
208}
209
210#[derive(Debug, Clone)]
214pub enum Error<I> {
215 I2c(I),
217 Ddc(ErrorCode),
219}
220
221impl<I> From<ErrorCode> for Error<I> {
222 fn from(e: ErrorCode) -> Self {
223 Error::Ddc(e)
224 }
225}
226
227impl<I: error::Error + Send + Sync + 'static> From<Error<I>> for io::Error {
228 fn from(e: Error<I>) -> io::Error {
229 match e {
230 Error::I2c(e) => io::Error::new(io::ErrorKind::Other, e),
231 Error::Ddc(e) => io::Error::new(io::ErrorKind::InvalidData, e),
232 }
233 }
234}
235
236impl<I: error::Error> error::Error for Error<I> {
237 fn description(&self) -> &str {
238 match *self {
239 Error::I2c(ref e) => error::Error::description(e),
240 Error::Ddc(ref e) => error::Error::description(e),
241 }
242 }
243
244 fn cause(&self) -> Option<&error::Error> {
245 match *self {
246 Error::I2c(ref e) => error::Error::cause(e),
247 Error::Ddc(ref e) => error::Error::cause(e),
248 }
249 }
250}
251
252impl<I: fmt::Display> fmt::Display for Error<I> {
253 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
254 match *self {
255 Error::I2c(ref e) => write!(f, "DDC/CI I2C error: {}", e),
256 Error::Ddc(ref e) => write!(f, "DDC/CI error: {}", e),
257 }
258 }
259}