#ifndef __PCI17x4API_HPP_INCLUDED__
#define __PCI17x4API_HPP_INCLUDED__

#include "drivers/linux/pci17x4/pci17x4.h"

class pci17x4 {
public:
  enum {
    NUMCHANNELS = 4,
  };
  enum range_t {
    RANGE_5_0V = PCI17X4_RANGE_5_0V,
    RANGE_2_5V = PCI17X4_RANGE_2_5V,
    RANGE_1_0V = PCI17X4_RANGE_1_0V,
    RANGE_0_5V = PCI17X4_RANGE_0_5V
  };
public:
  typedef int16_t datascan_t[NUMCHANNELS];
public:
 ~pci17x4();
public:
  static pci17x4 *open(const char *devname);
  static pci17x4 *open(int number, bool ul, bool ex);
public:
  bool configure(unsigned bufferscans, unsigned blockscans, unsigned toutms, bool usetrigger);
  double sampleRate();
  bool sampleRate(double rate);
  range_t range(unsigned ch);
  bool range(unsigned ch, range_t range);
  bool start();
  void stop();
  datascan_t *readScans(unsigned count);
  bool freeScans(const datascan_t *scans, unsigned count);
  unsigned bufferFull();
public:
  bool isUlBoard() const {
    return(_dmaStatus.ulboard != 0);
  }
  bool isRunning() const {
    return (_dmaStatus.running != 0);
  }
  double minSampleRate() const {
    return(isUlBoard() ? PCI1714_MINSAMPRATE_UL : PCI17X4_MINSAMPRATE);
  }
  double maxSampleRate() const {
    return(isUlBoard() ? PCI1714_MAXSAMPRATE_UL : PCI17X4_MAXSAMPRATE);
  }
  unsigned blockSize() const {
    return(1 << _dmaStatus.setup.blockshift);
  }
  unsigned blockScans() const {
    return(blockSize() / sizeof(datascan_t));
  }
  unsigned bufferSize() const {
    return(blockSize() * _dmaStatus.setup.numblocks);
  }
  unsigned bufferScans() const {
    return(blockScans() * _dmaStatus.setup.numblocks);
  }
  unsigned bufferBlocks() const {
    return(_dmaStatus.setup.numblocks);
  }
  const pci17x4_dmastatus_t &status() {
    return(_getStatus(), _dmaStatus);
  }
private:
  pci17x4(int fd);
  int _ioctl(int cmd, void *arg = NULL);
  uint32_t _inb(int port, bool immediate = false);
  uint32_t _inw(int port, bool immediate = false);
  uint32_t _inl(int port, bool immediate = false);
  bool _outb(int port, uint32_t data = 0, bool immediate = false);
  bool _outw(int port, uint32_t data = 0, bool immediate = false);
  bool _outl(int port, uint32_t data = 0, bool immediate = false);
  void _getStatus();
private:
  pci17x4_dmastatus_t _dmaStatus;
  uint64_t _readCount;
  uint64_t _freeCount;
  datascan_t *_dmaBuffer;
  uint32_t _rangeBits;
  int _fd;
private:
  datascan_t *_scan(uint64_t block) {
    return(_dmaBuffer + ((unsigned)(block % bufferBlocks()) * blockScans()));
  }
};

#endif /* whole file */
