#ifndef QSPI_C
#define QSPI_C

//----------------------------------
// Includes and forward declarations
//----------------------------------
#include "qspi.h"
#include <cyg/io/dac.h>
#include <pkgconf/io_dac.h>
#include <pkgconf/system.h>
#include <cyg/hal/hal_intr.h>

#include <math.h>

//----------------------
// Define some constants
//----------------------
#define QSPI_BAUD_10_0_MHz    2
#define QSPI_BAUD_6_67_MHz    3
#define QSPI_BAUD_5_00_MHz    4 // Do not go above this frequency for the AD7849
#define QSPI_BAUD_2_86_MHz    7
#define QSPI_BAUD_1_43_MHz   14
#define QSPI_BAUD_689_kHz    29
#define QSPI_BAUD_143_kHz   140
#define QSPI_BAUD_78_43_kHz 255

// Notice, updating 4 DACs at 2 kHz requires a synchronous clock of 
// 2 kHz * 16 bits * 4 dac = 128 kHz

//--------------------
// Function prototypes
//--------------------
static bool qspi_dac_init(struct cyg_devtab_entry * a_tab);
static Cyg_ErrNo qspi_dac_lookup(struct cyg_devtab_entry ** a_tab,
                                 struct cyg_devtab_entry * a_sub_tab,
                                 const char * a_name);
static void qspi_dac_write(dac_channel * a_channel, double a_value);
static bool qspi_dac_reset(dac_channel * a_chanel);

//------------------------------------
// Register the driver with the kernel
//------------------------------------
static DAC_FUNS(qsmcm_dac_funs,
                qspi_dac_write,
                qspi_dac_reset);

#ifdef CYGPKG_IO_DAC_QSPI_EC555_DAC_A
static qsmcm_dac_t qsmcm_dac_a = {
  (qsmcm_port_t *)CYGDAT_IO_QSPI_EC555_BASE_ADDRESS,
  CYGDAT_IO_DAC_QSPI_EC555_DAC_A_CHANNEL
};

DAC_CHANNEL(qsmcm_dac_channela,
            qsmcm_dac_funs,
            &qsmcm_dac_a,
            CYGDAT_IO_DAC_QSPI_EC555_DAC_A_SPAN,
            CYGDAT_IO_DAC_QSPI_EC555_DAC_A_SCALE,
            CYGDAT_IO_DAC_QSPI_EC555_DAC_A_OFFSET);

DEVTAB_ENTRY(qsmcm_io_dac0,
             CYGDAT_IO_DAC_QSPI_EC555_DAC_A_NAME,
             0,
             &dac_devio,
             qspi_dac_init,
             qspi_dac_lookup,
             &qsmcm_dac_channela);
#endif

#ifdef CYGPKG_IO_DAC_QSPI_EC555_DAC_B
static qsmcm_dac_t qsmcm_dac_b = {
  (qsmcm_port_t *)CYGDAT_IO_QSPI_EC555_BASE_ADDRESS,
  CYGDAT_IO_DAC_QSPI_EC555_DAC_B_CHANNEL
};

DAC_CHANNEL(qsmcm_dac_channelb,
            qsmcm_dac_funs,
            &qsmcm_dac_b,
            CYGDAT_IO_DAC_QSPI_EC555_DAC_B_SPAN,
            CYGDAT_IO_DAC_QSPI_EC555_DAC_B_SCALE,
            CYGDAT_IO_DAC_QSPI_EC555_DAC_B_OFFSET);

DEVTAB_ENTRY(qsmcm_io_dac1,
             CYGDAT_IO_DAC_QSPI_EC555_DAC_B_NAME,
             0,
             &dac_devio,
             qspi_dac_init,
             qspi_dac_lookup,
             &qsmcm_dac_channelb);
#endif

#ifdef CYGPKG_IO_DAC_QSPI_EC555_DAC_C
static qsmcm_dac_t qsmcm_dac_c = {
  (qsmcm_port_t *)CYGDAT_IO_QSPI_EC555_BASE_ADDRESS,
  CYGDAT_IO_DAC_QSPI_EC555_DAC_C_CHANNEL
};

DAC_CHANNEL(qsmcm_dac_channelc,
            qsmcm_dac_funs,
            &qsmcm_dac_c,
            CYGDAT_IO_DAC_QSPI_EC555_DAC_C_SPAN,
            CYGDAT_IO_DAC_QSPI_EC555_DAC_C_SCALE,
            CYGDAT_IO_DAC_QSPI_EC555_DAC_C_OFFSET);

DEVTAB_ENTRY(qsmcm_io_dac2,
             CYGDAT_IO_DAC_QSPI_EC555_DAC_C_NAME,
             0,
             &dac_devio,
             qspi_dac_init,
             qspi_dac_lookup,
             &qsmcm_dac_channelc);
#endif

#ifdef CYGPKG_IO_DAC_QSPI_DAC_D
static qsmcm_dac_t qsmcm_dac_d = {
  (qsmcm_port_t *)CYGDAT_IO_QSPI_EC555_BASE_ADDRESS,
  CYGDAT_IO_DAC_QSPI_EC555_DAC_D_CHANNEL
};

DAC_CHANNEL(qsmcm_dac_channeld,
            qsmcm_dac_funs,
            &qsmcm_dac_d,
            CYGDAT_IO_DAC_QSPI_EC555_DAC_D_SPAN,
            CYGDAT_IO_DAC_QSPI_EC555_DAC_D_SCALE,
            CYGDAT_IO_DAC_QSPI_EC555_DAC_D_OFFSET);

DEVTAB_ENTRY(qsmcm_io_dac3,
             CYGDAT_IO_DAC_QSPI_EC555_DAC_D_NAME,
             0,
             &dac_devio,
             qspi_dac_init,
             qspi_dac_lookup,
             &qsmcm_dac_channeld);
#endif

//-------------------------
// Functions implementation
//-------------------------
// qspi_dac_init
static bool qspi_dac_init(struct cyg_devtab_entry * a_tab)
{
  dac_channel * channel = (dac_channel *)a_tab->priv;
  qsmcm_dac_t * dac = (qsmcm_dac_t *)channel->m_dev_priv;
  qsmcm_port_t * qsmcm_port = dac->port;

  cyg_uint16 SPI_SCK_DEFAULT;
  switch(CYGDAT_IO_QSPI_EC555_SPEED)
  {
    case 5000: 
      SPI_SCK_DEFAULT = 4;
      break;
    case 4000: 
      SPI_SCK_DEFAULT = 5;
      break;
    case 3330: 
      SPI_SCK_DEFAULT = 3;
      break;
    case 2860: 
      SPI_SCK_DEFAULT = 7;
      break;
    case 2500: 
      SPI_SCK_DEFAULT = 8;
      break;
    case 2220: 
      SPI_SCK_DEFAULT = 9;
      break;
    case 2000: 
      SPI_SCK_DEFAULT = 10;
      break;
    case 1820: 
      SPI_SCK_DEFAULT = 11;
      break;
    case 1670: 
      SPI_SCK_DEFAULT = 12;
      break;
    case 1540: 
      SPI_SCK_DEFAULT = 13;
      break;
    case 1430: 
      SPI_SCK_DEFAULT = 14;
      break;
    case 689:  
      SPI_SCK_DEFAULT = 29;
      break;
    case 143:  
      SPI_SCK_DEFAULT = 140;
      break;
    case 78:   
      SPI_SCK_DEFAULT = 255;
      break;
    default:
      return false;
  }

//  port->portqs               // Is of no importance, gives the input or output of pins configured as general purpose IO
  qsmcm_port->pqspar_ddrqs = 0x7a7f; // Make MiSo general purpose input pin

  qsmcm_port->spcr0 = SPI_SCK_DEFAULT | 0x8100;    // CPOL = 0, CPHA = 1, Master mode, 16 bits, pins in normal mode
  qsmcm_port->spcr1 = 0;                           // No transfer delays, do not enable yet
  qsmcm_port->spcr2 = 0;                           // No wrap mode, do not use interrupts, queue is empty
  qsmcm_port->spcr3_spsr = 0;

  qsmcm_port->portqs |= 0x07ff;                    // Force pins high when qspi is inactive

  return true;
}

// qspi_dac_lookup
static Cyg_ErrNo qspi_dac_lookup(struct cyg_devtab_entry ** a_tab,
                                 struct cyg_devtab_entry * a_sub_tab,
                                 const char * a_name)
{ // Nothing special to do
  dac_channel * channel = (dac_channel *)(*a_tab)->priv;
  qsmcm_dac_t * dac = (qsmcm_dac_t *)(channel->m_dev_priv);
  qsmcm_port_t * qsmcm_port = dac->port;

  cyg_uint8 command = (dac->cmd_ram & 0x0F);
  command |= 0x40; // Use defaults for delay after transfer and PCS to SCK delay.
                   // Use the number of bits thats specified in SPCR0 per transfer.
                   // Return control of chip select to PORTQS after transfer.
  dac->cmd_ram = command;

  qsmcm_port->tran_ram[0] = 0;
  qsmcm_port->comd_ram[0] = command;            // Make a dumy transmit with the value zero. This assures that
                                                // the first time we try to send data to the SPIF flag will eventually appear.
  qsmcm_port->spcr3_spsr &= 0xff7f;             // Moreover, this way, every used dac will be reset to zero.
  qsmcm_port->spcr1 |= 0x8000;           

  return ENOERR;
}

// qspi_dac_reset
static bool qspi_dac_reset(dac_channel * a_channel)
{ // Do nothin for now, maybe later ...
  return true;
}

// qspi_dac_write
static void qspi_dac_write(dac_channel * a_channel, double a_value)
{
  CYG_INTERRUPT_STATE old_state;
  qsmcm_dac_t * dac = (qsmcm_dac_t *)(a_channel->m_dev_priv);
  qsmcm_port_t * qsmcm_port = dac->port;

  cyg_int16 tram = (cyg_int16)rint(a_value * 32767);

  HAL_DISABLE_INTERRUPTS(old_state);
  tram &= 0xfffc;                            // Only low level device drive knows the ata format the DAC expects

  while(!(qsmcm_port->spcr3_spsr & 0x0080)); // Wait for the previous transmit to complete
                                             // At full speed this will cost at most three microseconds. That's 
                                             // not too bad.

  qsmcm_port->tran_ram[0] = tram;
  qsmcm_port->comd_ram[0] = dac->cmd_ram;

  qsmcm_port->spcr3_spsr &= 0xff7f;          // Clear the SPIF flag
  qsmcm_port->spcr1 |= 0x8000;               // Enable the SPI
  HAL_RESTORE_INTERRUPTS(old_state);
}

#endif // QSPI_C
