#ifndef LINUX_BOARDTEST_SPITESTCLASS_H_
#define LINUX_BOARDTEST_SPITESTCLASS_H_

#include "OBSWConfig.h"

#ifdef XIPHOS_Q7S
#include "busConf.h"
#endif

#ifdef RASPBERRY_PI
#include <bsp_linux_board/definitions.h>
#endif

#include <fsfw_hal/common/gpio/GpioIF.h>
#include <fsfw_hal/linux/spi/SpiCookie.h>
#include <test/testtasks/TestTask.h>

#include <vector>

#include "devices/gpioIds.h"

struct SusTestCfg {
  SusTestCfg(bool doTest, gpioId_t gpioId) : gpioId(gpioId) {}
  bool doTest = false;
  const gpioId_t gpioId;
  bool intConv = true;
  bool extConv = false;
};

struct Max1227TestCfg {
  bool testRadSensorExtConvWithDelay = false;
  bool testRadSensorIntConv = false;
  bool plPcduAdcExtConv = false;
  bool plPcduAdcExtConvAsOne = false;
  bool plPcduAdcIntConv = false;
  bool vbatSwitch = true;

  SusTestCfg testSus[12] = {
      {false, gpioIds::CS_SUS_0}, {false, gpioIds::CS_SUS_1},  {false, gpioIds::CS_SUS_2},
      {false, gpioIds::CS_SUS_3}, {false, gpioIds::CS_SUS_4},  {false, gpioIds::CS_SUS_5},
      {false, gpioIds::CS_SUS_6}, {false, gpioIds::CS_SUS_7},  {false, gpioIds::CS_SUS_8},
      {false, gpioIds::CS_SUS_9}, {false, gpioIds::CS_SUS_10}, {false, gpioIds::CS_SUS_11},
  };
};
class SpiTestClass : public TestTask {
 public:
  enum TestModes { NONE, MGM_LIS3MDL, MGM_RM3100, GYRO_L3GD20H, MAX1227 };

  TestModes testMode;

  SpiTestClass(object_id_t objectId, GpioIF* gpioIF);

  ReturnValue_t performOneShotAction() override;
  ReturnValue_t performPeriodicAction() override;

 private:
  GpioIF* gpioIF;
  Max1227TestCfg adcCfg = {};

  std::array<uint8_t, 128> recvBuffer;
  std::array<uint8_t, 128> sendBuffer;
  struct spi_ioc_transfer spiTransferStruct[6] = {};

  void performRm3100Test(uint8_t mgmId);
  void performLis3MdlTest(uint8_t lis3Id);
  void performL3gTest(uint8_t l3gId);
  void performOneShotMax1227Test();
  void performPeriodicMax1227Test();
  void performMax1227Test();

  /* ACS board specific code which pulls all GPIOs high */
  void acsInit();

  /* ACS board specific variables */
#ifdef RASPBERRY_PI
  uint8_t mgm0Lis3mdlChipSelect = gpio::MGM_0_BCM_PIN;
  uint8_t mgm1Rm3100ChipSelect = gpio::MGM_1_BCM_PIN;
  uint8_t mgm2Lis3mdlChipSelect = gpio::MGM_2_BCM_PIN;
  uint8_t mgm3Rm3100ChipSelect = gpio::MGM_3_BCM_PIN;

  uint8_t gyro0AdisChipSelect = gpio::GYRO_0_BCM_PIN;
  uint8_t gyro1L3gd20ChipSelect = gpio::GYRO_1_BCM_PIN;
  uint8_t gyro2AdisChipSelect = gpio::GYRO_2_BCM_PIN;
  uint8_t gyro3L3gd20ChipSelect = gpio::GYRO_3_BCM_PIN;
#else

  uint8_t mgm0Lis3mdlChipSelect = 0;
  uint8_t mgm1Rm3100ChipSelect = 0;
  uint8_t gyro0AdisResetLine = 0;
  uint8_t gyro0AdisChipSelect = 0;
  uint8_t gyro1L3gd20ChipSelect = 0;
  uint8_t gyro2L3gd20ChipSelect = 0;
  uint8_t mgm2Lis3mdlChipSelect = 0;
  uint8_t mgm3Rm3100ChipSelect = 0;
#endif

  static constexpr uint8_t STM_READ_MASK = 0b1000'0000;
  static constexpr uint8_t RM3100_READ_MASK = STM_READ_MASK;
  static constexpr uint8_t STM_AUTO_INCR_MASK = 0b0100'0000;

  void shiftOutZeros();
  void setSendBuffer();

  void max1227RadSensorTest(int fd);
  void max1227SusTest(int fd, SusTestCfg& cfg);
  void max1227PlPcduTest(int fd);

  void setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed);

  void writeStmRegister(int fd, gpioId_t chipSelect, uint8_t reg, uint8_t value,
                        bool autoIncrement);
  void writeMultipleStmRegisters(int fd, gpioId_t chipSelect, uint8_t reg, uint8_t* values,
                                 size_t len);
  void writeMultipleRegisters(int fd, gpioId_t chipSelect, uint8_t reg, uint8_t* values,
                              size_t len);
  void writeRegister(int fd, gpioId_t chipSelect, uint8_t reg, uint8_t value);
  ReturnValue_t transfer(int fd, gpioId_t chipSelect);

  uint8_t readRm3100Register(int fd, gpioId_t chipSelect, uint8_t reg);
  uint8_t readStmRegister(int fd, gpioId_t chipSelect, uint8_t reg, bool autoIncrement);
  uint8_t readRegister(int fd, gpioId_t chipSelect, uint8_t reg);
  void readMultipleStmRegisters(int fd, gpioId_t chipSelect, uint8_t reg, uint8_t* reply,
                                size_t len);
  void readMultipleRegisters(int fd, gpioId_t chipSelect, uint8_t reg, uint8_t* reply, size_t len);
};

#endif /* LINUX_BOARDTEST_SPITESTCLASS_H_ */