st7305-lcd 0.2.0

Platform-independent no_std driver for the Sitronix ST7305 reflective LCD controller (embedded-hal 1.0, blocking and async)
Documentation
/// Orientation of the logical (drawing) coordinate system relative to the
/// native one, i.e. to the `W` x `H` layout of the GRAM described by a
/// [`PixelMap`](super::pixel_map::PixelMap).
///
/// The picture is turned **clockwise** by the given angle, as in most display
/// drivers: with `Deg90` the logical top-left corner of the picture lands in
/// the native top-right corner, the logical size is `H` x `W` and a logical
/// `(x, y)` is the native `(W - 1 - y, x)`. To read it you turn the device
/// counter-clockwise by the same angle.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Rotation {
    /// Logical = native, size `W` x `H`
    #[default]
    Deg0,
    /// Size `H` x `W`, native `(W - 1 - y, x)`
    Deg90,
    /// Size `W` x `H`, native `(W - 1 - x, H - 1 - y)`
    Deg180,
    /// Size `H` x `W`, native `(y, H - 1 - x)`
    Deg270,
}

impl Rotation {
    /// Logical size for a native `w` x `h` layout.
    pub const fn size(self, w: u32, h: u32) -> (u32, u32) {
        match self {
            Rotation::Deg0 | Rotation::Deg180 => (w, h),
            Rotation::Deg90 | Rotation::Deg270 => (h, w),
        }
    }

    /// Converts a logical `(x, y)` into the native `(xn, yn)` of a `w` x `h`
    /// layout. `None` if `(x, y)` is outside the logical size.
    pub const fn to_native(self, w: u32, h: u32, x: u32, y: u32) -> Option<(u32, u32)> {
        let (lw, lh) = self.size(w, h);
        if x >= lw || y >= lh {
            return None;
        }
        Some(match self {
            Rotation::Deg0 => (x, y),
            Rotation::Deg90 => (w - 1 - y, x),
            Rotation::Deg180 => (w - 1 - x, h - 1 - y),
            Rotation::Deg270 => (y, h - 1 - x),
        })
    }
}

const _: () = assert!(matches!(Rotation::Deg0.size(400, 300), (400, 300)));
const _: () = assert!(matches!(Rotation::Deg90.size(400, 300), (300, 400)));
const _: () = assert!(matches!(Rotation::Deg180.size(400, 300), (400, 300)));
const _: () = assert!(matches!(Rotation::Deg270.size(400, 300), (300, 400)));

// The logical origin lands in a different native corner for every orientation.
const _: () = assert!(matches!(
    Rotation::Deg0.to_native(400, 300, 0, 0),
    Some((0, 0))
));
const _: () = assert!(matches!(
    Rotation::Deg90.to_native(400, 300, 0, 0),
    Some((399, 0))
));
const _: () = assert!(matches!(
    Rotation::Deg180.to_native(400, 300, 0, 0),
    Some((399, 299))
));
const _: () = assert!(matches!(
    Rotation::Deg270.to_native(400, 300, 0, 0),
    Some((0, 299))
));
const _: () = assert!(Rotation::Deg90.to_native(400, 300, 300, 0).is_none());
const _: () = assert!(Rotation::Deg90.to_native(400, 300, 0, 400).is_none());