// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::rc::Rc;
use std::str::FromStr;
use structopt::StructOpt;
use thiserror::Error;

use super::eeprom;
use crate::app::TransportWrapper;
use crate::impl_serializable_error;
use crate::util::voltage::Voltage;

#[derive(Clone, Debug, StructOpt, Serialize, Deserialize)]
pub struct SpiParams {
    #[structopt(long, help = "SPI instance")]
    pub bus: Option<String>,

    #[structopt(long, help = "SPI bus speed")]
    pub speed: Option<u32>,

    #[structopt(long, help = "SPI bus voltage", parse(try_from_str = Voltage::from_str))]
    pub voltage: Option<Voltage>,

    #[structopt(long, help = "SPI polarity/phase mode", parse(try_from_str = TransferMode::from_str))]
    pub mode: Option<TransferMode>,
}

impl SpiParams {
    pub fn create(
        &self,
        transport: &TransportWrapper,
        default_instance: &str,
    ) -> Result<Rc<dyn Target>> {
        let spi = transport.spi(self.bus.as_deref().unwrap_or(default_instance))?;
        if let Some(speed) = self.speed {
            spi.set_max_speed(speed)?;
        }
        if let Some(voltage) = self.voltage {
            spi.set_voltage(voltage)?;
        }
        if let Some(mode) = self.mode {
            spi.set_transfer_mode(mode)?;
        }
        Ok(spi)
    }
}

/// Errors related to the SPI interface and SPI transactions.
#[derive(Error, Debug, Serialize, Deserialize)]
pub enum SpiError {
    #[error("Invalid option: {0}")]
    InvalidOption(String),
    #[error("Invalid word size: {0}")]
    InvalidWordSize(u32),
    #[error("Invalid speed: {0}")]
    InvalidSpeed(u32),
    #[error("Invalid data length: {0}")]
    InvalidDataLength(usize),
    #[error("Mismatched data length: {0} != {1}")]
    MismatchedDataLength(usize, usize),
    #[error("Invalid transfer mode: {0}")]
    InvalidTransferMode(String),
}
impl_serializable_error!(SpiError);

/// Represents the SPI transfer mode.
/// See https://en.wikipedia.org/wiki/Serial_Peripheral_Interface#Clock_polarity_and_phase
/// for details about SPI transfer modes.
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum TransferMode {
    /// `Mode0` is CPOL=0, CPHA=0.
    Mode0,
    /// `Mode1` is CPOL=0, CPHA=1.
    Mode1,
    /// `Mode2` is CPOL=1, CPHA=0.
    Mode2,
    /// `Mode3` is CPOL=1, CPHA=1.
    Mode3,
}

impl FromStr for TransferMode {
    type Err = SpiError;
    fn from_str(s: &str) -> std::result::Result<TransferMode, Self::Err> {
        match s {
            "Mode0" | "mode0" | "0" => Ok(TransferMode::Mode0),
            "Mode1" | "mode1" | "1" => Ok(TransferMode::Mode1),
            "Mode2" | "mode2" | "2" => Ok(TransferMode::Mode2),
            "Mode3" | "mode3" | "3" => Ok(TransferMode::Mode3),
            _ => Err(SpiError::InvalidTransferMode(s.to_string())),
        }
    }
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum ClockPhase {
    SampleLeading,
    SampleTrailing,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum ClockPolarity {
    IdleLow,
    IdleHigh,
}

impl TransferMode {
    pub fn phase(&self) -> ClockPhase {
        match self {
            TransferMode::Mode0 | TransferMode::Mode2 => ClockPhase::SampleLeading,
            TransferMode::Mode1 | TransferMode::Mode3 => ClockPhase::SampleTrailing,
        }
    }
    pub fn polarity(&self) -> ClockPolarity {
        match self {
            TransferMode::Mode0 | TransferMode::Mode1 => ClockPolarity::IdleLow,
            TransferMode::Mode2 | TransferMode::Mode3 => ClockPolarity::IdleHigh,
        }
    }
}

/// Represents a SPI transfer.
pub enum Transfer<'rd, 'wr> {
    Read(&'rd mut [u8]),
    Write(&'wr [u8]),
    Both(&'wr [u8], &'rd mut [u8]),
}

/// A trait which represents a SPI Target.
pub trait Target {
    /// Gets the current SPI transfer mode.
    fn get_transfer_mode(&self) -> Result<TransferMode>;
    /// Sets the current SPI transfer mode.
    fn set_transfer_mode(&self, mode: TransferMode) -> Result<()>;

    /// Gets the current number of bits per word.
    fn get_bits_per_word(&self) -> Result<u32>;
    /// Sets the current number of bits per word.
    fn set_bits_per_word(&self, bits_per_word: u32) -> Result<()>;

    /// Gets the maximum allowed speed of the SPI bus.
    fn get_max_speed(&self) -> Result<u32>;
    /// Sets the maximum allowed speed of the SPI bus.
    fn set_max_speed(&self, max_speed: u32) -> Result<()>;

    /// Returns the maximum number of transfers allowed in a single transaction.
    fn get_max_transfer_count(&self) -> Result<usize>;

    /// Maximum chunksize handled by this SPI device.
    fn max_chunk_size(&self) -> Result<usize>;

    fn set_voltage(&self, _voltage: Voltage) -> Result<()> {
        Err(SpiError::InvalidOption("This target does not support set_voltage".to_string()).into())
    }

    /// Runs a SPI transaction composed from the slice of [`Transfer`] objects.  Will assert the
    /// CS for the duration of the entire transactions.
    fn run_transaction(&self, transaction: &mut [Transfer]) -> Result<()>;

    /// Runs a number of EEPROM/FLASH protocol SPI transactions.  Will assert and deassert CS for
    /// each transaction.
    fn run_eeprom_transactions(&self, transactions: &mut [eeprom::Transaction]) -> Result<()> {
        // Default implementation translates into generic SPI read/write, which works as long as
        // the transport supports generic SPI transfers of sufficint length, and that the mode is
        // single-data-wire.
        for transfer in transactions {
            match transfer {
                eeprom::Transaction::Command(cmd) => {
                    self.run_transaction(&mut [Transfer::Write(cmd.to_bytes()?)])?
                }
                eeprom::Transaction::Read(cmd, rbuf) => self.run_transaction(&mut [
                    Transfer::Write(cmd.to_bytes()?),
                    Transfer::Read(rbuf),
                ])?,
                eeprom::Transaction::Write(cmd, wbuf) => self.run_transaction(&mut [
                    Transfer::Write(cmd.to_bytes()?),
                    Transfer::Write(wbuf),
                ])?,
                eeprom::Transaction::WaitForBusyClear => {
                    while {
                        let mut buf = [0u8; 1];
                        self.run_transaction(&mut [
                            Transfer::Write(&[eeprom::READ_STATUS]),
                            Transfer::Read(&mut buf),
                        ])?;
                        buf[0]
                    } & eeprom::STATUS_WIP
                        != 0
                    {}
                }
            }
        }
        Ok(())
    }

    /// Assert the CS signal.  Uses reference counting, will be deasserted when each and every
    /// returned `AssertChipSelect` object have gone out of scope.
    fn assert_cs(self: Rc<Self>) -> Result<AssertChipSelect>;
}

/// Object that keeps the CS asserted, deasserting when it goes out of scope, (unless another
/// instance keeps CS asserted longer.)
pub struct AssertChipSelect {
    target: Rc<dyn TargetChipDeassert>,
}

impl AssertChipSelect {
    // Needs to be public in order for implementation of `Target` to be able to call it.  Never
    // called by users of `Target`.
    pub fn new(target: Rc<dyn TargetChipDeassert>) -> Self {
        Self { target }
    }
}

impl Drop for AssertChipSelect {
    fn drop(&mut self) {
        self.target.deassert_cs()
    }
}

// Needs to be public in order for implementation of `Target` to be able to implement it.  Never
// called by users of `Target`.
pub trait TargetChipDeassert {
    fn deassert_cs(&self);
}
