ecc608-linux 0.2.4

A library for accessing the ECC608 chip on Linux
Documentation
use crate::{Error, Result};
use bitfield::bitfield;
use std::{fmt, str::FromStr};

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Zone {
    Data,
    Config,
}

impl FromStr for Zone {
    type Err = Error;

    fn from_str(s: &str) -> Result<Self> {
        match s.to_lowercase().as_str() {
            "data" => Ok(Self::Data),
            "config" => Ok(Self::Config),
            _ => Err(Error::invalid_address()),
        }
    }
}

impl fmt::Display for Zone {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Config => f.write_str("config"),
            Self::Data => f.write_str("data"),
        }
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum DataBuffer {
    TempKey,
    MessageDigest,
    AlternateKey,
}

impl From<&DataBuffer> for u8 {
    fn from(v: &DataBuffer) -> Self {
        match v {
            DataBuffer::TempKey => 0,
            DataBuffer::MessageDigest => 1,
            DataBuffer::AlternateKey => 2,
        }
    }
}

impl From<u8> for DataBuffer {
    fn from(v: u8) -> Self {
        match v & 3 {
            0 => Self::TempKey,
            1 => Self::MessageDigest,
            2 => Self::AlternateKey,
            _ => unreachable!(),
        }
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Address {
    Otp(OffsetAddress),
    Config(OffsetAddress),
    Data(DataAddress),
}

bitfield! {
    #[derive(PartialEq, Eq, Clone, Copy)]
    pub struct OffsetAddress(u16);
    impl Debug;
    u8, offset, set_offset: 10, 8;
    u8, block, set_block: 12, 11;
}

bitfield! {
    #[derive(PartialEq, Clone, Copy, Eq)]
    pub struct DataAddress(u16);
    impl Debug;
    u8, block, set_block: 3, 0;
    u8, offset, set_offset: 10, 8;
    u8, slot, set_slot: 14, 11;
}

impl From<&Address> for u16 {
    fn from(v: &Address) -> Self {
        match v {
            Address::Otp(addr) => addr.0,
            Address::Config(addr) => addr.0,
            Address::Data(addr) => addr.0,
        }
    }
}

impl Address {
    pub fn otp(block: u8, offset: u8) -> Result<Self> {
        if block > 4 || offset > 7 {
            return Err(Error::invalid_address());
        }
        let mut address = OffsetAddress(0);
        address.set_block(block);
        address.set_offset(offset);
        Ok(Self::Otp(address))
    }

    pub fn config(block: u8, offset: u8) -> Result<Self> {
        if block > 4 || offset > 7 {
            return Err(Error::invalid_address());
        }
        let mut address = OffsetAddress(0);
        address.set_block(block);
        address.set_offset(offset);
        Ok(Self::Config(address))
    }

    pub fn slot_config(slot: u8) -> Result<Self> {
        if slot > 15 {
            return Err(Error::invalid_address());
        }
        let (block, offset) = if slot <= 5 {
            (0, (20 + slot * 2) >> 2)
        } else {
            (1, ((slot - 5) * 2) >> 2)
        };
        Self::config(block, offset)
    }

    pub fn key_config(slot: u8) -> Result<Self> {
        if slot > 15 {
            return Err(Error::invalid_address());
        }
        Self::config(3, (slot * 2) >> 2)
    }

    pub fn data(slot: u8, block: u8, offset: u8) -> Result<Self> {
        if slot > 15
            || (slot < 8 && block > 1)
            || (slot == 8 && block > 15)
            || (slot > 8 && block > 7)
        {
            return Err(Error::invalid_address());
        }
        let mut address = DataAddress(0);
        address.set_block(block);
        address.set_offset(offset);
        address.set_slot(slot);
        Ok(Self::Data(address))
    }

    pub fn zone(&self) -> u8 {
        match self {
            Self::Config(_) => 0x00,
            Self::Otp(_) => 0x01,
            Self::Data(_) => 0x02,
        }
    }
}