1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//! A driver for the KSZ8863 Ethernet Switch.
//!
//! This driver is split into two main modules:
//!
//! - [`miim`](./miim/index.html) for the MII Management Interface (MIIM).
//! - [`smi`](./smi/index.html) for the Serial Management Interface (SMI).
//!
//! While these two terms often refer to same protocol, their usage in the KSZ8863 documentation
//! refers to two distinct protocols and sets of registers. Please refer to the datasheet for
//! details.
//!
//! These modules contain a type and module for every documented register along with typed access
//! to each of their respective fields. High-level read/write/modify access to these registers are
//! provided via the `Miim` and `Smi` types respectively.
//!
//! *Note that the SPI and I2C interfaces are not currently supported, though PRs are welcome.*
//!
//! # Usage
//!
//! At the foundation of this crate are the `miim::{Read, Write}` and `smi::{Read, Write}` traits.
//! The first step is to implement these for your respective MIIM and SMI interfaces. For details
//! on how to implement these, visit sections `3.3.10` and `3.3.11` of the datasheet.
//!
//! Implementing these traits unlocks high level access via the [`Smi`](./smi/struct.Smi.html) and
//! [`Miim`](./miim/struct.Miim.html) interface type wrappers. These types provide short-hand
//! methods for reading, writing and modifying registers and their individual fields. The provided
//! API for these types is inspired by the `svd2rust` crate.
//!
//! Here is an example of using the `Miim`.
//!
//! ```rust
//! use ksz8863::{miim, Miim};
//!
//! fn main() {
//! #    let miim_iface = miim::Map::default();
//!     // Wrap the type that impls the Read/Write traits with `Miim`.
//!     // Note: We could also wrap `&mut miim_iface` here if we only local scope access is needed.
//!     let mut miim = Miim(miim_iface);
//!
//!     // Specify which phy we want to communicate with via its PHY address.
//!     let mut phy = miim.phy(0);
//!
//!     // Read the value of the "Basic Control Register".
//!     assert_eq!(phy.bcr().read().unwrap(), miim::Bcr::default());
//!
//!     // Modify the "Force 100BT" field of the "Basic Control Register" in place.
//!     let mut bcr = phy.bcr();
//!     assert!(bcr.read().unwrap().read().force_fd().bit_is_clear());
//!     bcr.modify(|w| w.force_fd().set_bit()).unwrap();
//!     let reg = bcr.read().unwrap();
//!     assert!(reg != miim::Bcr::default());
//!     assert!(reg.read().force_fd().bit_is_set());
//! }
//! ```
//!
//! The `Smi` API is similar, but we don't need to specify a PHY address.
//!
//! ```rust
//! use ksz8863::{smi, Smi};
//!
//! fn main() {
//! #    let smi_iface = smi::Map::default();
//!     let mut smi = Smi(smi_iface);
//!     assert_eq!(smi.gc1().read().unwrap(), smi::Gc1::default());
//!     smi.gc1().modify(|w| w.tx_flow_control().clear_bit()).unwrap();
//!     assert!(smi.gc1().read().unwrap() != smi::Gc1::default());
//! }
//! ```
//!
//! ## Extras
//!
//! The `Address` type in each module represents the unique index at which the register is located.
//!
//! The `State` type from each module is a dynamic representation of register state, useful for
//! storing the state of multiple registers in a collection.
//!
//! The `Map` type from each module is a collection that is guaranteed to contain the state of all
//! registers. This is useful for remotely monitoring the state of registers while reducing I/O,
//! and for simulating an MIIM/SMI interface in the case that you don't have access to one.
//!
//! # Features
//!
//! - `hash-32` provides `Hash32` implementations from the `hash32` crate.
//! - `serde` provides `Deserialize` and `Serialize` implementations.
//! - `ufmt` provides `ufmt::uDebug` implementations.
//!
//! All of these features are **opt-in** and disabled by default.

#![no_std]
#![recursion_limit = "256"]

#[macro_use]
mod macros;
pub mod miim;
pub mod smi;

pub use miim::Miim;
pub use smi::Smi;

/// The error returned when no attempting to produce an `Address` from an unknown byte.
#[derive(Debug)]
pub struct InvalidAddress;

/// Allow for using bit values (1 and 0) as default values in register macro.
trait IntoBool {
    /// Convert `self` into a `bool`.
    fn into_bool(self) -> bool;
}

impl IntoBool for bool {
    fn into_bool(self) -> bool {
        self
    }
}

impl IntoBool for u8 {
    fn into_bool(self) -> bool {
        self != 0
    }
}