/*
 * AMS_CAN.c
 *
 *  Created on: Mar 19, 2022
 *      Author: jasper
 */

#include "AMS_CAN.h"

#include "ADBMS_Abstraction.h"


#include "common_defs.h"
#include "main.h"
#include "AMS_HighLevel.h"
#include "stm32f3xx.h"
#include "stm32f3xx_hal.h"
#include "stm32f3xx_hal_can.h"

#include <stdint.h>

int PENDING_MESSAGE_HANDLE = 0;
uint8_t canTestData[8] = {0,0,0,0,0,0,0,0};


CAN_HandleTypeDef* ams_can_handle;

void ams_can_init(CAN_HandleTypeDef* ams_handle,
                  CAN_HandleTypeDef* car_handle) {
  ams_can_handle = ams_handle;

  // Start peripheral
  if (HAL_CAN_Start(ams_can_handle) != HAL_OK) {
    ams_can_handle = car_handle;
    if (HAL_CAN_Start(ams_can_handle) != HAL_OK) {
      Error_Handler();
    }
  }

  // Config filter
  CAN_FilterTypeDef can_filter;
  can_filter.FilterActivation = CAN_FILTER_ENABLE;
  can_filter.FilterBank = 0;
  can_filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
  /* Message ID is in the MSBs of the FilterId register */
  can_filter.FilterIdHigh = CAN_ID_CLOCK_SYNC << (16 - 11);
  can_filter.FilterIdLow = 0;
  /* Filter the 11 MSBs (i.e. a StdId) */

  if(BMS_IN_TEST_MODE == 1){
	  can_filter.FilterMaskIdHigh = BMS_TEST_ID; // alleNachrichtenIds werden akzeptiert
  }else{
	  can_filter.FilterMaskIdHigh = 0xFFE0;
  }

  can_filter.FilterMaskIdLow = 0;
  can_filter.FilterMode = CAN_FILTERMODE_IDMASK;
  can_filter.FilterScale = CAN_FILTERSCALE_32BIT;
  can_filter.SlaveStartFilterBank = 0;
  if (HAL_CAN_ConfigFilter(ams_can_handle, &can_filter) != HAL_OK) {
    Error_Handler();
  }
  can_filter.FilterBank++;
  can_filter.FilterIdHigh = CAN_ID_MASTER_HEARTBEAT << (16 - 11);
  can_filter.FilterIdLow = 0;
  if (HAL_CAN_ConfigFilter(ams_can_handle, &can_filter) != HAL_OK) {
    Error_Handler();
  }

  // Activate RX notifications
  if (HAL_CAN_ActivateNotification(ams_can_handle,
                                   CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) {
    Error_Handler();
  }
}

static int cb_triggered = 0;

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef* handle) {
  static CAN_RxHeaderTypeDef header;
  static uint8_t data[8];
  cb_triggered = 1;

  if (HAL_CAN_GetRxMessage(handle, CAN_RX_FIFO0, &header, data) != HAL_OK) {
    Error_Handler();
  }

  if (handle == ams_can_handle) {
    ams_can_handle_ams_msg(&header, data);
  } else {
    Error_Handler();
  }
}

void ams_can_handle_ams_msg(CAN_RxHeaderTypeDef* header, uint8_t* data) {

  if(BMS_IN_TEST_MODE == 1){
		  PENDING_MESSAGE_HANDLE = 1;
		  for(int i = 0; i < 8; i++){
			  canTestData[i] = data[i];
		  }
		  return;
  }


  if (header->IDE != CAN_ID_STD) {
    return;
  }

  switch (header->StdId) {
  case CAN_ID_CLOCK_SYNC:
//    clock_sync_handle_clock_sync_frame(data[0]);
    break;
  case CAN_ID_MASTER_HEARTBEAT:
//    clock_sync_handle_master_heartbeat();
    break;
  }
}

void ams_can_send_heartbeat() {
  static CAN_TxHeaderTypeDef header;
  static uint8_t data[8];

  header.IDE = CAN_ID_STD;
  header.DLC = 8;
  header.RTR = CAN_RTR_DATA;
  header.TransmitGlobalTime = DISABLE;

  // Send voltages
  for (int msg_id = 0; msg_id < 5; msg_id++) {
    header.StdId = CAN_ID_AMS_SLAVE_HEARTBEAT_BASE | (0 << 4) | msg_id; //TODO: Use slave_id/new format
    for (int i = 0; i < 4; i++) {
      int cell = msg_id * 4 + i;
      uint16_t v = (cell < N_CELLS) ? module.cellVoltages[cell] : 0;
      data[2 * i + 0] = v & 0xFF;
      data[2 * i + 1] = v >> 8;
    }
    if (ams_can_wait_for_free_mailboxes(ams_can_handle, 1,
                                        CAN_HEARTBEAT_TX_TIMEOUT) == HAL_OK) {
      uint32_t mailbox;
      HAL_CAN_AddTxMessage(ams_can_handle, &header, data, &mailbox);
    }
  }

  // Send temperatures
  /*for (int temp_msg_id = 0; temp_msg_id < 8; temp_msg_id++) {
    int msg_id = temp_msg_id + 3;
    header.StdId = CAN_ID_AMS_SLAVE_HEARTBEAT_BASE | (slave_id << 4) | msg_id;
    for (int i = 0; i < 4; i++) {
      int sensor = temp_msg_id * 4 + i;
      uint16_t temp = temperatures[sensor];
      data[2 * i + 0] = temp & 0xFF;
      data[2 * i + 1] = temp >> 8;
    }
    if (ams_can_wait_for_free_mailboxes(ams_can_handle, 1,
                                        CAN_HEARTBEAT_TX_TIMEOUT) == HAL_OK) {
      uint32_t mailbox;
      HAL_CAN_AddTxMessage(ams_can_handle, &header, data, &mailbox);
    }
  }*/
}

/*void ams_can_send_error(AMS_ErrorCode error_code,
                        uint32_t transmission_timeout) {
  static CAN_TxHeaderTypeDef header;
  header.IDE = CAN_ID_STD;
  header.DLC = 8;
  header.RTR = CAN_RTR_DATA;
  header.TransmitGlobalTime = DISABLE;
  header.StdId = CAN_ID_SLAVE_ERROR;

  static uint8_t data[8];
  data[0] = slave_id;
  data[1] = error_code;

  HAL_CAN_AbortTxRequest(ams_can_handle,
                         CAN_TX_MAILBOX0 | CAN_TX_MAILBOX1 | CAN_TX_MAILBOX2);
  uint32_t mailbox;
  HAL_CAN_AddTxMessage(ams_can_handle, &header, data, &mailbox);
  ams_can_wait_for_free_mailboxes(ams_can_handle, 3, transmission_timeout);
}*/

HAL_StatusTypeDef ams_can_wait_for_free_mailboxes(CAN_HandleTypeDef* handle,
                                                  int num_mailboxes,
                                                  uint32_t timeout) {
  uint32_t end = HAL_GetTick() + timeout;
  while (HAL_GetTick() < end) {
    if (HAL_CAN_GetTxMailboxesFreeLevel(handle) >= num_mailboxes) {
      return HAL_OK;
    }
  }
  return HAL_TIMEOUT;
}
