/*
 * Slave_Monitoring.c
 *
 *  Created on: Jun 15, 2022
 *      Author: max
 */

#include "Slave_Monitoring.h"

#include "AMS_Errorcodes.h"
#include "main.h"

#include "stm32g4xx_hal.h"
#include "stm32g4xx_hal_gpio.h"

#include <stdint.h>
#include <string.h>

SlaveHandler slaves[N_SLAVES];
uint16_t min_voltage, max_voltage;
int16_t min_temp, max_temp;

void initSlaves() {
  HAL_GPIO_WritePin(SLAVES_ENABLE_GPIO_Port, SLAVES_ENABLE_Pin, GPIO_PIN_RESET);
  HAL_GPIO_WritePin(BOOT0_FF_DATA_GPIO_Port, BOOT0_FF_DATA_Pin, GPIO_PIN_RESET);

  for (int i = 0; i < N_SLAVES + 5; i++) {
    HAL_GPIO_WritePin(BOOT0_FF_CLK_GPIO_Port, BOOT0_FF_CLK_Pin, GPIO_PIN_SET);
    HAL_Delay(1);
    HAL_GPIO_WritePin(BOOT0_FF_CLK_GPIO_Port, BOOT0_FF_CLK_Pin, GPIO_PIN_RESET);
    HAL_Delay(1);
  }

  HAL_Delay(5);
  HAL_GPIO_WritePin(SLAVES_ENABLE_GPIO_Port, SLAVES_ENABLE_Pin, GPIO_PIN_SET);

  for (int n = 0; n < N_SLAVES; n++) {
    for (int i = 0; i < N_TEMP_SENSORS; i++)
      slaves[n].cellTemps[i] = 0;

    for (int j = 0; j < N_CELLS_SERIES; j++)
      slaves[n].cellVoltages[j] = 32768;

    slaves[n].error = 0;
    slaves[n].timeout = 0;
    slaves[n].timestamp = HAL_GetTick();
    slaves[n].slaveID = n;
    for (int i = 0; i < SLAVE_HEARTBEAT_FRAMES; i++) {
      slaves[n].frame_timestamps[i] = HAL_GetTick();
    }
  }
}

uint8_t checkSlaves() {
  if (HAL_GetTick() < 10000) {
    return 0;
  }

  min_voltage = UINT16_MAX;
  max_voltage = 0;
  min_temp = INT16_MAX;
  max_temp = INT16_MIN;
  for (int n = 0; n < N_SLAVES; n++) {
    if (((int)(HAL_GetTick() - slaves[n].timestamp)) > SLAVETIMEOUT) {
      slaves[n].timeout = 1;

      AMSErrorHandle timeouterror;
      timeouterror.errorcode = AMS_ERROR_SLAVE_TIMEOUT;
      timeouterror.errorarg[0] = n;

      AMS_Error_Handler(&timeouterror);
      return 1;
    }

    if (slaves[n].error) {
      AMSErrorHandle errorframe;
      errorframe.errorcode = AMS_ERROR_SLAVE_PANIC;
      memcpy(errorframe.errorarg, slaves[n].error_frame, 7);
      AMS_Error_Handler(&errorframe);
      return 1;
    }

    for (int i = 0; i < SLAVE_HEARTBEAT_FRAMES; i++) {
      if ((int)(HAL_GetTick() - slaves[n].frame_timestamps[i]) >
          SLAVETIMEOUT * 2) {
        slaves[n].timeout = 1;
        AMSErrorHandle timeouterror;
        timeouterror.errorcode = AMS_ERROR_SLAVE_FRAME_TIMEOUT;
        timeouterror.errorarg[0] = n;
        timeouterror.errorarg[1] = i;
        AMS_Error_Handler(&timeouterror);
        return 1;
      }
    }

    for (int i = 0; i < N_CELLS_SERIES; i++) {
      uint16_t v = slaves[n].cellVoltages[i];
      if (v > max_voltage) {
        max_voltage = v;
      }
      if (v < min_voltage) {
        min_voltage = v;
      }
    }

    int working_cell_temps = 0;
    for (int i = 0; i < N_TEMP_SENSORS; i++) {
      int16_t t = slaves[n].cellTemps[i];
      if (t != 0) {
        working_cell_temps++;
        if (t > max_temp) {
          max_temp = t;
        }
        if (t < min_temp) {
          min_temp = t;
        }
      }
    }
    if (working_cell_temps < SLAVE_MIN_TEMP_SENSORS) {
      AMSErrorHandle temperror;
      temperror.errorcode = AMS_ERROR_SLAVE_TOO_FEW_TEMPS;
      temperror.errorarg[0] = n;
      AMS_Error_Handler(&temperror);
      return 1;
    }
  }

  AMSErrorHandle thresherror;
  thresherror.errorcode = AMS_ERROR_MASTER_THRESH;
  int error = 0;
  if (min_temp < THRESH_UT) {
    error = 1;
    thresherror.errorarg[0] = AMS_ERRORARG_MASTER_THRESH_UT;
  } else if (max_temp > THRESH_OT) {
    error = 1;
    thresherror.errorarg[0] = AMS_ERRORARG_MASTER_THRESH_OT;
  } else if (min_voltage < THRESH_UV) {
    error = 1;
    thresherror.errorarg[0] = AMS_ERRORARG_MASTER_THRESH_UV;
  } else if (max_voltage > THRESH_OV) {
    error = 1;
    thresherror.errorarg[0] = AMS_ERRORARG_MASTER_THRESH_OV;
  }

  if (error) {
    AMS_Error_Handler(&thresherror);
  }

  return 0;
}
