//! Non-blocking I²C transaction contract. //! //! Controllers own in-flight transfer storage. Implementations may use //! interrupts or DMA, but must never make a driver wait for a peripheral //! status flag. #![no_std] use kaptan_time::Timestamp; /// Terminal outcome reported by an I²C controller. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum I2cCompletion { /// The bound interrupt had no terminal transaction event. NotPending, /// The submitted transaction completed and read bytes are valid. Complete, /// The submitted transaction failed and read bytes are unusable. TransferFault, } /// Completion admission or cancellation failure. Errors never copy read bytes. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum CompletionError { NotPending, NotActive, InvalidLength, TransferFault, /// Physical STOP was not observed by the shutdown deadline. The controller /// is halted and cannot accept another transaction during this boot. StopUnproven, } /// Owns a non-blocking I²C controller route and its in-flight storage. /// /// Each operation sends a STOP on successful completion. Controllers copy a /// submitted write into owned storage before returning. A completed read is /// copied into the caller-provided destination only from /// [`Self::complete_transaction`], after the hardware no longer accesses the /// controller-owned storage. This avoids retaining pointers to caller slices /// across interrupt boundaries. pub trait I2cBus { /// Failure to submit a transaction. type StartError; /// Starts one address-scoped write transaction ending with a STOP. fn start_write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::StartError>; /// Starts one address-scoped read transaction ending with a STOP. fn start_read(&mut self, address: u8, length: usize) -> Result<(), Self::StartError>; /// Releases controller ownership after a hardware ISR acknowledged the /// terminal event and, for a successful read, copies into `read`. /// /// This must not poll or wait. `NotPending` is entirely nonmutating. A /// successful read requires a matching destination length and controller /// proof of the current transaction's STOP, not just a caller notification. /// Old IRQs/completions must not retire or copy out a newer transaction. fn complete_transaction( &mut self, completion: I2cCompletion, read: Option<&mut [u8]>, ) -> Result<(), CompletionError>; /// Cancels an in-flight transaction after a platform-selected timeout. /// /// Requests STOP without waiting. Admission remains closed until STOP is /// proven. This is not permission to reuse or free in-flight storage. fn cancel_transaction(&mut self, now: Timestamp); /// Services cancellation deadlines even without interrupts. The caller must /// invoke this periodically with its monotonic boot clock. A bounded STOP /// failure halts admission and returns `StopUnproven`. Storage must outlive /// all hardware access, including owner drop/forget and failed cancellation. fn service(&mut self, now: Timestamp) -> Result<(), CompletionError>; }