/*
 * SPI_Slave_Communication.c
 *
 *  Created on: Jun 16, 2022
 *      Author: max
 */

#include "SPI_Slave_Communication.h"

#include "stm32g4xx_hal.h"
#include "stm32g4xx_hal_crc.h"
#include "stm32g4xx_hal_def.h"
#include "stm32g4xx_hal_spi.h"
#include "stm32g4xx_hal_spi_ex.h"

#include <stdint.h>

#define SPI_BUFFER_SIZE 1024
#define DUMMYBYTES 2

#define SPI_TIMEOUT 10

SPI_HandleTypeDef* spibus;

extern ErrorFlags errorflags;

uint8_t spirxbuf[SPI_BUFFER_SIZE];
uint8_t spitxbuf[SPI_BUFFER_SIZE];
static volatile int spi_transfer_complete;
uint8_t command;

AIRStateHandler* spi_airstates;

AMSErrorHandle* spierrorinfo;

void set_SPI_errorInfo(AMSErrorHandle* errorinfo) { spierrorinfo = errorinfo; }

void spi_communication_init(SPI_HandleTypeDef* spi,
                            AIRStateHandler* airstatemaschine) {
  spibus = spi;
  spi_airstates = airstatemaschine;
  command = 0xFF;
  HAL_SPI_DeInit(spi);
  // HAL_SPI_Receive_IT(spibus, &command, 1);
}

// void setShuntdata() {

//   uint8_t status = receiveData(12);
//   if (status == HAL_OK) {
//     spi_airstates->BatteryVoltageBatterySide =
//         spirxbuf[0] << 24 | spirxbuf[1] << 16 | spirxbuf[2] << 8 |
//         spirxbuf[3];
//     spi_airstates->BatteryVoltageVehicleSide =
//         spirxbuf[4] << 24 | spirxbuf[5] << 16 | spirxbuf[6] << 8 |
//         spirxbuf[7];
//     uint32_t current = spirxbuf[8] << 24 | spirxbuf[9] << 16 |
//                        spirxbuf[10] << 8 | spirxbuf[11];
//   }
// }

// void setTSState() {
//   uint8_t status = receiveData(1);
//   if (status == HAL_OK) {
//     spi_airstates->targetTSState = spirxbuf[0];
//   }
// }

// void getTSState() {

//   spitxbuf[0] = spi_airstates->currentTSState;
//   spitxbuf[1] = (uint8_t)(spi_airstates->targetTSState);
//   spitxbuf[2] = (uint8_t)(spi_airstates->RelaisSupplyVoltage >> 8) & 0xFF;
//   spitxbuf[3] = (uint8_t)(spi_airstates->RelaisSupplyVoltage & 0xFF);
//   spitxbuf[4] = (uint8_t)((spi_airstates->ShutdownCircuitVoltage >> 8) &
//   0xFF); spitxbuf[5] = (uint8_t)(spi_airstates->ShutdownCircuitVoltage &
//   0xFF); spitxbuf[6] = (uint8_t)((spi_airstates->AIRNegativeCurrent >> 8) &
//   0xFF); spitxbuf[7] = (uint8_t)(spi_airstates->AIRNegativeCurrent & 0xFF);
//   spitxbuf[8] = (uint8_t)((spi_airstates->AIRPositiveCurrent >> 8) & 0xFF);
//   spitxbuf[9] = (uint8_t)((spi_airstates->AIRPositiveCurrent) & 0xFF);
//   spitxbuf[10] = (uint8_t)((spi_airstates->AIRPrechargeCurrent >> 8) & 0xFF);
//   spitxbuf[11] = (uint8_t)((spi_airstates->AIRPrechargeCurrent) & 0xFF);
//   spitxbuf[12] =
//       (uint8_t)((spi_airstates->BatteryVoltageBatterySide >> 24) & 0xFF);
//   spitxbuf[13] =
//       (uint8_t)((spi_airstates->BatteryVoltageBatterySide >> 16) & 0xFF);
//   spitxbuf[14] =
//       (uint8_t)((spi_airstates->BatteryVoltageBatterySide >> 8) & 0xFF);
//   spitxbuf[15] =
//       (uint8_t)((spi_airstates->BatteryVoltageBatterySide >> 0) & 0xFF);
//   spitxbuf[16] =
//       (uint8_t)((spi_airstates->BatteryVoltageVehicleSide >> 24) & 0xFF);
//   spitxbuf[17] =
//       (uint8_t)((spi_airstates->BatteryVoltageVehicleSide >> 16) & 0xFF);
//   spitxbuf[18] =
//       (uint8_t)((spi_airstates->BatteryVoltageVehicleSide >> 8) & 0xFF);
//   spitxbuf[19] =
//       (uint8_t)((spi_airstates->BatteryVoltageVehicleSide >> 0) & 0xFF);

//   transmitData(20);
// }

// void getError() {

//   spitxbuf[0] = spierrorinfo->errorcode;
//   spitxbuf[1] = spierrorinfo->errorarg[0];
//   spitxbuf[2] = spierrorinfo->errorarg[1];
//   spitxbuf[3] = spierrorinfo->errorarg[2];
//   spitxbuf[4] = spierrorinfo->errorarg[3];
//   spitxbuf[5] = spierrorinfo->errorarg[4];
//   spitxbuf[6] = spierrorinfo->errorarg[5];
//   spitxbuf[7] = spierrorinfo->errorarg[6];
//   spitxbuf[8] = spierrorinfo->errorarg[7];
//   spitxbuf[9] = (errorflags.AMS_ERROR_LED << 7) |
//                 (errorflags.IMD_ERROR_LED << 6) | (errorflags.IMD_ERROR << 5)
//                 | (errorflags.HV_inactive << 4) |
//                 (errorflags.TS_no_voltage_error << 3) |
//                 (errorflags.negative_AIR_error << 2) |
//                 (errorflags.positive_AIR_or_PC_error << 1) |
//                 (errorflags.positive_AIR_and_PC_open);
//   spitxbuf[10] = (errorflags.negative_AIR_open);
//   spitxbuf[11] = calculateChecksum(spitxbuf, 10);

//   transmitData(12);
// }

// void togglestatusLED() {
//   HAL_GPIO_TogglePin(Status_LED_GPIO_Port, Status_LED_Pin);
// }

// void getMeasurements() {

//   for (int n = 0; n < NUMBEROFSLAVES; n++) {
//     spitxbuf[n * 89] = slaves[n].slaveID;
//     spitxbuf[n * 89 + 1] = (uint8_t)((slaves[n].timestamp >> 24) & 0xFF);
//     spitxbuf[n * 89 + 2] = (uint8_t)((slaves[n].timestamp >> 16) & 0xFF);
//     spitxbuf[n * 89 + 3] = (uint8_t)((slaves[n].timestamp >> 8) & 0xFF);
//     spitxbuf[n * 89 + 4] = (uint8_t)((slaves[n].timestamp >> 0) & 0xFF);

//     for (int i = 0; i < NUMBEROFCELLS; i++) {
//       spitxbuf[n * 89 + 5 + 2 * i] =
//           (uint8_t)((slaves[n].cellVoltages[i] >> 8) & 0xFF);
//       spitxbuf[n * 89 + 6 + 2 * i] =
//           (uint8_t)((slaves[n].cellVoltages[i]) & 0xFF);
//     }
//     for (int i = 0; i < NUMBEROFTEMPS; i++) {
//       spitxbuf[n * 89 + 25 + 2 * i] =
//           (uint8_t)((slaves[n].cellTemps[i] >> 8) & 0xFF);
//       spitxbuf[n * 89 + 26 + 2 * i] =
//           (uint8_t)((slaves[n].cellTemps[i]) & 0xFF);
//     }
//   }

//   transmitData(NUMBEROFSLAVES * 89);
// }

// uint8_t receiveData(uint16_t length) {
//   if (length > 1024)
//     return 0xFF;

//   HAL_GPIO_WritePin(Inter_STM_IRQ_GPIO_Port, Inter_STM_IRQ_Pin,
//   GPIO_PIN_SET); HAL_StatusTypeDef status =
//       HAL_SPI_Receive(spibus, spirxbuf, length, SPI_TIMEOUT);
//   HAL_GPIO_WritePin(Inter_STM_IRQ_GPIO_Port, Inter_STM_IRQ_Pin,
//   GPIO_PIN_RESET); return (uint8_t)status;
// }

// uint8_t transmitData(uint16_t length) {
//   if (length > 1024)
//     return 0xFF;

//   HAL_GPIO_WritePin(Inter_STM_IRQ_GPIO_Port, Inter_STM_IRQ_Pin,
//   GPIO_PIN_SET); HAL_StatusTypeDef status =
//       HAL_SPI_Transmit(spibus, spitxbuf, length, SPI_TIMEOUT);
//   HAL_GPIO_WritePin(Inter_STM_IRQ_GPIO_Port, Inter_STM_IRQ_Pin,
//   GPIO_PIN_RESET); return (uint8_t)status;
// }

void checkSPI() {
  /*
          if(commandreceived)
          {
                  commandreceived = 0;
                  switch(command)
                  {
                  case SET_SHUNTDATA:
                          setShuntdata();
                  break;

                  case SET_TSSTATE:
                          setTSState();
                  break;

                  case GET_TSSTATE:
                          getTSState();
                  break;

                  case GET_ERROR:
                          getError();
                  break;

                  case TOGGLE_STATUS_LED:
                          togglestatusLED();
                  break;

                  case GET_MEASUREMENTS:
                          getMeasurements();
                  break;

                  default:
                  break;
                  }

                  HAL_SPI_Receive_IT(spibus, &command, 1);

          }
          else
          {
                  if(spibus->State == HAL_SPI_STATE_READY)
                  {
                          HAL_SPI_Receive_IT(spibus, &command, 1);
                  }
          }
  */
  InterSTMFrame();
}

// uint8_t checkXor(uint8_t *buf, uint8_t len) {
//   uint8_t checksum = 0xFF;
//   for (int i = 0; i < len; i++) {
//     checksum ^= buf[i];
//   }

//   if (checksum == buf[len]) {
//     return 0;
//   } else {
//     return 1;
//   }
// }

uint8_t calculateChecksum(uint8_t* buf, uint8_t len) {
  uint8_t checksum = 0xFF;
  for (int i = 0; i < len; i++) {
    checksum ^= buf[i];
  }
  return checksum;
}

void InterSTMFrame() {

  HAL_GPIO_TogglePin(Status_LED_GPIO_Port, Status_LED_Pin);
  if (HAL_GPIO_ReadPin(Inter_STM_CS_GPIO_Port, Inter_STM_CS_Pin) ==
      GPIO_PIN_RESET) {
    return;
  }

  for (int n = 0; n < NUMBEROFSLAVES; n++) {
    spitxbuf[n * 89] = slaves[n].slaveID;
    spitxbuf[n * 89 + 1] = (uint8_t)((slaves[n].timestamp >> 24) & 0xFF);
    spitxbuf[n * 89 + 2] = (uint8_t)((slaves[n].timestamp >> 16) & 0xFF);
    spitxbuf[n * 89 + 3] = (uint8_t)((slaves[n].timestamp >> 8) & 0xFF);
    spitxbuf[n * 89 + 4] = (uint8_t)((slaves[n].timestamp >> 0) & 0xFF);

    for (int i = 0; i < NUMBEROFCELLS; i++) {
      spitxbuf[n * 89 + 5 + 2 * i] =
          (uint8_t)((slaves[n].cellVoltages[i] >> 8) & 0xFF);
      spitxbuf[n * 89 + 6 + 2 * i] =
          (uint8_t)((slaves[n].cellVoltages[i]) & 0xFF);
    }
    for (int i = 0; i < NUMBEROFTEMPS; i++) {
      spitxbuf[n * 89 + 25 + 2 * i] =
          (uint8_t)((slaves[n].cellTemps[i] >> 8) & 0xFF);
      spitxbuf[n * 89 + 26 + 2 * i] =
          (uint8_t)((slaves[n].cellTemps[i]) & 0xFF);
    }
  }

  uint16_t errorcodebaseaddress = NUMBEROFSLAVES * 89 + 1;

  spitxbuf[errorcodebaseaddress + 0] = spierrorinfo->errorcode;
  spitxbuf[errorcodebaseaddress + 1] = spierrorinfo->errorarg[0];
  spitxbuf[errorcodebaseaddress + 2] = spierrorinfo->errorarg[1];
  spitxbuf[errorcodebaseaddress + 3] = spierrorinfo->errorarg[2];
  spitxbuf[errorcodebaseaddress + 4] = spierrorinfo->errorarg[3];
  spitxbuf[errorcodebaseaddress + 5] = spierrorinfo->errorarg[4];
  spitxbuf[errorcodebaseaddress + 6] = spierrorinfo->errorarg[5];
  spitxbuf[errorcodebaseaddress + 7] = spierrorinfo->errorarg[6];
  spitxbuf[errorcodebaseaddress + 8] = spierrorinfo->errorarg[7];
  spitxbuf[errorcodebaseaddress + 9] =
      (errorflags.AMS_ERROR_LED << 7) | (errorflags.IMD_ERROR_LED << 6) |
      (errorflags.IMD_ERROR << 5) | (errorflags.HV_inactive << 4) |
      (errorflags.TS_no_voltage_error << 3) |
      (errorflags.negative_AIR_error << 2) |
      (errorflags.positive_AIR_or_PC_error << 1) |
      (errorflags.positive_AIR_and_PC_open);
  spitxbuf[errorcodebaseaddress + 10] = (errorflags.negative_AIR_open);
  spitxbuf[errorcodebaseaddress + 11] = calculateChecksum(spitxbuf, 10);

  uint16_t tsstatebaseaddress = errorcodebaseaddress + 12;

  spitxbuf[tsstatebaseaddress + 0] = spi_airstates->currentTSState;
  spitxbuf[tsstatebaseaddress + 1] = (uint8_t)(spi_airstates->targetTSState);
  spitxbuf[tsstatebaseaddress + 2] = (uint8_t)(0) & 0xFF;
  spitxbuf[tsstatebaseaddress + 3] = (uint8_t)(0);
  spitxbuf[tsstatebaseaddress + 4] = (uint8_t)((0) & 0xFF);
  spitxbuf[tsstatebaseaddress + 5] = (uint8_t)(0);
  spitxbuf[tsstatebaseaddress + 6] = (uint8_t)((0) & 0xFF);
  spitxbuf[tsstatebaseaddress + 7] = (uint8_t)(0);
  spitxbuf[tsstatebaseaddress + 8] = (uint8_t)((0) & 0xFF);
  spitxbuf[tsstatebaseaddress + 9] = (uint8_t)((0) & 0xFF);
  spitxbuf[tsstatebaseaddress + 10] = (uint8_t)((0) & 0xFF);
  spitxbuf[tsstatebaseaddress + 11] = (uint8_t)((0) & 0xFF);
  spitxbuf[tsstatebaseaddress + 12] =
      (uint8_t)((spi_airstates->BatteryVoltageBatterySide >> 24) & 0xFF);
  spitxbuf[tsstatebaseaddress + 13] =
      (uint8_t)((spi_airstates->BatteryVoltageBatterySide >> 16) & 0xFF);
  spitxbuf[tsstatebaseaddress + 14] =
      (uint8_t)((spi_airstates->BatteryVoltageBatterySide >> 8) & 0xFF);
  spitxbuf[tsstatebaseaddress + 15] =
      (uint8_t)((spi_airstates->BatteryVoltageBatterySide >> 0) & 0xFF);
  spitxbuf[tsstatebaseaddress + 16] =
      (uint8_t)((spi_airstates->BatteryVoltageVehicleSide >> 24) & 0xFF);
  spitxbuf[tsstatebaseaddress + 17] =
      (uint8_t)((spi_airstates->BatteryVoltageVehicleSide >> 16) & 0xFF);
  spitxbuf[tsstatebaseaddress + 18] =
      (uint8_t)((spi_airstates->BatteryVoltageVehicleSide >> 8) & 0xFF);
  spitxbuf[tsstatebaseaddress + 19] =
      (uint8_t)((spi_airstates->BatteryVoltageVehicleSide >> 0) & 0xFF);

  uint32_t spitimeoutcounter = HAL_GetTick();

  HAL_SPI_DeInit(spibus);
  HAL_SPI_Init(spibus);
  HAL_SPIEx_FlushRxFifo(spibus);
  spi_transfer_complete = 0;
  HAL_SPI_Receive_IT(spibus, spirxbuf, 13);
  HAL_GPIO_WritePin(Inter_STM_IRQ_GPIO_Port, Inter_STM_IRQ_Pin, GPIO_PIN_SET);
  uint32_t timeout = HAL_GetTick() + SPI_FRAME_TIMEOUT;
  while (!spi_transfer_complete && HAL_GetTick() < timeout) {
  }
  HAL_GPIO_WritePin(Inter_STM_IRQ_GPIO_Port, Inter_STM_IRQ_Pin, GPIO_PIN_RESET);
  if (!spi_transfer_complete) {
    HAL_SPI_Abort(spibus);
    return;
  }

  spi_airstates->BatteryVoltageBatterySide =
      spirxbuf[0] << 24 | spirxbuf[1] << 16 | spirxbuf[2] << 8 | spirxbuf[3];
  spi_airstates->BatteryVoltageVehicleSide =
      spirxbuf[4] << 24 | spirxbuf[5] << 16 | spirxbuf[6] << 8 | spirxbuf[7];
  uint32_t current =
      spirxbuf[8] << 24 | spirxbuf[9] << 16 | spirxbuf[10] << 8 | spirxbuf[11];
  spi_airstates->targetTSState = spirxbuf[12];
}

void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef* hspi) {
  HAL_SPI_Transmit_IT(spibus, spitxbuf, NUMBEROFSLAVES * 89 + 33);
}

void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef* hspi) {
  spi_transfer_complete = 1;
}

// void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi) {
//   __HAL_SPI_CLEAR_OVRFLAG(hspi);
//   // HAL_SPI_Receive_IT(spibus, &command, 1);
//   HAL_SPIEx_FlushRxFifo(hspi);
// }