From e4fdd1a8824a035699967ce689b868f760a386fc Mon Sep 17 00:00:00 2001
From: Diego Barrios Romero <eldruin@gmail.com>
Date: Fri, 17 Jul 2020 22:38:11 +0200
Subject: [PATCH] Support embedded-time without Error trait

---
 Cargo.toml                      |  4 ++
 examples/embedded_time_linux.rs | 17 +++++++
 src/embedded_time.rs            | 79 +++++++++++++++++++++++++++++++++
 src/lib.rs                      |  4 +-
 4 files changed, 103 insertions(+), 1 deletion(-)
 create mode 100644 examples/embedded_time_linux.rs
 create mode 100644 src/embedded_time.rs

diff --git a/Cargo.toml b/Cargo.toml
index c388af2..cbd9edd 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -27,6 +27,7 @@ coveralls = { repository = "eldruin/ds323x-rs", branch = "master", service = "gi
 [dependencies]
 embedded-hal = "0.2.3"
 rtcc = "0.2"
+embedded-time = "0.7.1"
 
 [dev-dependencies]
 linux-embedded-hal = "0.3"
@@ -34,3 +35,6 @@ embedded-hal-mock = "0.7"
 
 [profile.release]
 lto = true
+
+[patch.crates-io]
+embedded-time = { git="https://github.com/eldruin/embedded-time.git", branch="remove-error-trait" }
\ No newline at end of file
diff --git a/examples/embedded_time_linux.rs b/examples/embedded_time_linux.rs
new file mode 100644
index 0000000..6ba0c09
--- /dev/null
+++ b/examples/embedded_time_linux.rs
@@ -0,0 +1,17 @@
+use ds323x::{Ds323x, Ds323xWrapper, NaiveDate, Rtcc};
+use embedded_time::{duration::units::Hours, Clock};
+use linux_embedded_hal::I2cdev;
+
+fn main() {
+    let dev = I2cdev::new("/dev/i2c-1").unwrap();
+    let mut rtc = Ds323x::new_ds3231(dev);
+    let datetime = NaiveDate::from_ymd(2020, 5, 1).and_hms(19, 59, 58);
+    rtc.set_datetime(&datetime).unwrap();
+    let rtc = Ds323xWrapper::from(rtc);
+    // do something else...
+    let instant = rtc.now().unwrap();
+    let hours_since_epoch = instant.duration_since_epoch::<Hours>().unwrap();
+    println!("Hours since epoch: {}", hours_since_epoch);
+
+    let _dev = rtc.into_inner().destroy_ds3231();
+}
diff --git a/src/embedded_time.rs b/src/embedded_time.rs
new file mode 100644
index 0000000..544a737
--- /dev/null
+++ b/src/embedded_time.rs
@@ -0,0 +1,79 @@
+//! embedded-time `Clock` implementation
+
+use crate::{
+    interface::{ReadData, WriteData},
+    Ds323x, Error, Rtcc,
+};
+use core::cell::RefCell;
+use core::convert::From;
+use embedded_time::{clock, Clock, Instant, Period};
+
+/// Wrapper error
+#[derive(Debug)]
+pub enum WrapperError<CommE, PinE> {
+    /// Device could not be acquired. It may be already acquired.
+    CouldNotAcquireDevice,
+    /// Other error
+    Other(Error<CommE, PinE>),
+}
+
+/// Wrapper around `Ds323x` driver to support `embedded-time`.
+pub struct Ds323xWrapper<DI, IC> {
+    dev: RefCell<Ds323x<DI, IC>>,
+}
+
+impl<CommE, PinE, DI, IC> Clock for Ds323xWrapper<DI, IC>
+where
+    DI: ReadData<Error = Error<CommE, PinE>> + WriteData<Error = Error<CommE, PinE>>,
+{
+    /// Number of non-leap-seconds since January 1, 1970 UTC
+    type Rep = u64;
+    const PERIOD: Period = Period::new(1, 1);
+    type ImplError = WrapperError<CommE, PinE>;
+
+    fn now(&self) -> Result<Instant<Self>, clock::Error<Self::ImplError>> {
+        let datetime = self
+            .dev
+            .try_borrow_mut()
+            .map_err(|_| clock::Error::Other(Self::ImplError::CouldNotAcquireDevice))?
+            .get_datetime()
+            .map_err(|e| clock::Error::Other(Self::ImplError::Other(e)))?;
+        Ok(Instant::new((datetime.timestamp_millis() as u64) / 1_000))
+    }
+}
+
+impl<CommE, PinE, DI, IC> From<Ds323x<DI, IC>> for Ds323xWrapper<DI, IC>
+where
+    DI: ReadData<Error = Error<CommE, PinE>> + WriteData<Error = Error<CommE, PinE>>,
+{
+    fn from(dev: Ds323x<DI, IC>) -> Self {
+        Ds323xWrapper {
+            dev: RefCell::new(dev),
+        }
+    }
+}
+
+impl<DI, IC> Ds323xWrapper<DI, IC> {
+    /// Return inner `Ds323x` driver instance.
+    pub fn into_inner(self) -> Ds323x<DI, IC> {
+        self.dev.into_inner()
+    }
+}
+/*
+impl<CommE, PinE, DI, IC> Ds323xWrapper<DI, IC>
+where
+    DI: ReadData<Error = Error<CommE, PinE>> + WriteData<Error = Error<CommE, PinE>>,
+{
+    /// Run function on mutable borrowed inner device
+    pub fn do_on_borrow_mut<R>(
+        &self,
+        f: impl FnOnce(RefMut<Ds323x<DI, IC>>) -> Result<R, Error<CommE, PinE>>,
+    ) -> Result<R, WrapperError<CommE, PinE>> {
+        let dev = self
+            .dev
+            .try_borrow_mut()
+            .map_err(|_| WrapperError::<CommE, PinE>::CouldNotAcquireDevice)?;
+        f(dev).map_err(WrapperError::Other)
+    }
+}
+*/
diff --git a/src/lib.rs b/src/lib.rs
index 0639307..59b2c0d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -400,7 +400,7 @@ pub const SPI_MODE_1: Mode = MODE_1;
 pub const SPI_MODE_3: Mode = MODE_3;
 
 /// All possible errors in this crate
-#[derive(Debug)]
+#[derive(Debug, PartialEq, Eq)]
 pub enum Error<CommE, PinE> {
     /// I²C/SPI bus error
     Comm(CommE),
@@ -514,6 +514,8 @@ pub use crate::ds323x::{
 mod ds3231;
 mod ds3232;
 mod ds3234;
+mod embedded_time;
+pub use crate::embedded_time::{Ds323xWrapper, WrapperError};
 
 mod private {
     use super::{ic, interface};