/*
  CAN总线上的设备1到7
  将所有CAN总线上挂载的设备抽象成单个设备进行管理和控制
*/

/* Includes ----------------------------------------------------------------- */
#include "can_use.h"
#include "user_math.h"
#include "device.h"
#include "error_detect.h"
#define CAN_MOTOR_ENC_RES (8191)  /* 电机编码器分辨率 */
#define CAN_MOTOR_CUR_RES (16384) 


#define CAN_GM6020_CTRL_ID_BASE (0x1ff)
#define CAN_PITCH6020_CTRL_ID (0x2ff)

#define CAN_G3508_CTRL_ALL_ID (0x200)
#define CAN_VESC_CTRL_ID_BASE (0x300)


#define CAN_MOTOR_TX_BUF_SIZE (8)
#define CAN_MOTOR_RX_BUF_SIZE (8)


/*电机最大电流绝对值*/
#define CAN_GM6020_MAX_ABS_CUR (20)
#define CAN_M3508_MAX_ABS_CUR (20)
#define CAN_M2006_MAX_ABS_CUR (10)

static CAN_RawRx_t raw_rx1;//原始的can数据
static CAN_RawRx_t raw_rx2;
CAN_RawTx_t raw_tx;


/*用于can原始数据，传入消息队列*/
static CAN_t *gcan;

/* Private function  -------------------------------------------------------- */

static void CAN_DJIMotor_Decode(CAN_MotorFeedback_t *feedback,
                             const uint8_t *raw) {
  if (feedback == NULL || raw == NULL) return;
  uint16_t raw_ecd = (uint16_t)((raw[0] << 8) | raw[1]);
  int16_t raw_current = (int16_t)((raw[4] << 8) | raw[5]);
	feedback->rotor_speed = (int16_t)((raw[2] << 8) | raw[3]);
  feedback->temp = raw[6]; 															 
														 
  feedback->rotor_ecd = raw_ecd ;
  feedback->torque_current =
  raw_current * CAN_GM6020_MAX_ABS_CUR / (float)CAN_MOTOR_CUR_RES;														 
}
static void CAN_Sick_Receive(CAN_SickFeedback_t *feedback,
	                            const uint8_t *raw) {
	if (feedback == NULL || raw == NULL) return;			
	feedback->raw_dis[0] = (uint16_t)((raw[0] << 8) | raw[1]);														
	feedback->raw_dis[1] = (uint16_t)((raw[2] << 8) | raw[3]);																
	feedback->raw_dis[2] = (uint16_t)((raw[4] << 8) | raw[5]);
  feedback->raw_dis[3]= (uint16_t)((raw[6] << 8) | raw[7]);	
   																
}
static void CAN_VescMotor_Decode_1(CAN_MotorFeedback_t *feedback,
                             const uint8_t *raw)
{
  if (feedback == NULL || raw == NULL) return;												 
	 union 
	{
		int x;
		uint8_t data[4];
	}speed;
	
	 speed.data[0]= raw[3];
	 speed.data[1]= raw[2];
	 speed.data[2]= raw[1];
	 speed.data[3]= raw[0];
   feedback->rotor_speed = speed.x;
   union
	 {
		 int16_t y;
		 uint8_t dat[2];
	 }current;
	 current.dat[0]= raw[5];
	 current.dat[1]= raw[4];
	 feedback->torque_current =(fp32)current.y/10;
}

static void CAN_CAN1RxFifoMsgPendingCallback(void) {
  HAL_CAN_GetRxMessage(BSP_CAN_GetHandle(BSP_CAN_1), CAN_RX_FIFO0,
                       &raw_rx1.rx_header, raw_rx1.rx_data);
	raw_rx1.hcan =BSP_CAN_GetHandle(BSP_CAN_1);
  osMessageQueuePut(gcan->msgq_raw, &raw_rx1, 0, 0);
}

static void CAN_CAN2RxFifoMsgPendingCallback(void) {
  HAL_CAN_GetRxMessage(BSP_CAN_GetHandle(BSP_CAN_2), CAN_RX_FIFO1,
                       &raw_rx2.rx_header, raw_rx2.rx_data);
	
  raw_rx2.hcan =BSP_CAN_GetHandle(BSP_CAN_2);
  osMessageQueuePut(gcan->msgq_raw, &raw_rx2, 0, 0);
}

/* Exported functions ------------------------------------------------------- */
int8_t CAN_Init(CAN_t *can, const CAN_Params_t *param) {
  if (can == NULL) return DEVICE_ERR_NULL;

  can->msgq_raw = osMessageQueueNew(32, sizeof(CAN_RawRx_t), NULL);

  can->param = param;

  CAN_FilterTypeDef can_filter = {0};

  can_filter.FilterBank = 0;
  can_filter.FilterIdHigh = 0;
  can_filter.FilterIdLow = 0;
  can_filter.FilterMode = CAN_FILTERMODE_IDMASK;
  can_filter.FilterScale = CAN_FILTERSCALE_32BIT;
  can_filter.FilterMaskIdHigh = 0;
  can_filter.FilterMaskIdLow = 0;
  can_filter.FilterActivation = ENABLE;
  can_filter.SlaveStartFilterBank = 14;
  can_filter.FilterFIFOAssignment = CAN_RX_FIFO0;

  HAL_CAN_ConfigFilter(BSP_CAN_GetHandle(BSP_CAN_1), &can_filter);
  HAL_CAN_Start(BSP_CAN_GetHandle(BSP_CAN_1));
  BSP_CAN_RegisterCallback(BSP_CAN_1, HAL_CAN_RX_FIFO0_MSG_PENDING_CB,
                           CAN_CAN1RxFifoMsgPendingCallback);
  HAL_CAN_ActivateNotification(BSP_CAN_GetHandle(BSP_CAN_1),
                               CAN_IT_RX_FIFO0_MSG_PENDING);

  can_filter.FilterBank = 14;
  can_filter.FilterFIFOAssignment = CAN_RX_FIFO1;

  HAL_CAN_ConfigFilter(BSP_CAN_GetHandle(BSP_CAN_2), &can_filter);
  HAL_CAN_Start(BSP_CAN_GetHandle(BSP_CAN_2));
  BSP_CAN_RegisterCallback(BSP_CAN_2, HAL_CAN_RX_FIFO1_MSG_PENDING_CB,
                           CAN_CAN2RxFifoMsgPendingCallback);
  HAL_CAN_ActivateNotification(BSP_CAN_GetHandle(BSP_CAN_2),
                               CAN_IT_RX_FIFO1_MSG_PENDING);

  gcan = can;
  return DEVICE_OK;
}

int8_t CAN_DJIMotor_Control(CAN_MotorGroup_e group, CAN_Output_t *output,
                         CAN_t *can) {
  if (output == NULL) return DEVICE_ERR_NULL;

  int16_t motor1, motor2, motor3, motor4, motor5 ;

  switch (group) {
		
    case CAN_MOTOR_CHASSIS6020:
      motor1 =
          (int16_t)(output->chassis6020.named.m1);
      motor2 =
          (int16_t)(output->chassis6020.named.m2);
      motor3 =
          (int16_t)(output->chassis6020.named.m3);
      motor4 =
          (int16_t)(output->chassis6020.named.m4);

      raw_tx.tx_header.StdId = CAN_GM6020_CTRL_ID_BASE;
      raw_tx.tx_header.IDE = CAN_ID_STD;
      raw_tx.tx_header.RTR = CAN_RTR_DATA;
      raw_tx.tx_header.DLC = CAN_MOTOR_TX_BUF_SIZE;

      raw_tx.tx_data[0] = (uint8_t)((motor1 >> 8) & 0xFF);
      raw_tx.tx_data[1] = (uint8_t)(motor1 & 0xFF);
      raw_tx.tx_data[2] = (uint8_t)((motor2 >> 8) & 0xFF);
      raw_tx.tx_data[3] = (uint8_t)(motor2 & 0xFF);
      raw_tx.tx_data[4] = (uint8_t)((motor3 >> 8) & 0xFF);
      raw_tx.tx_data[5] = (uint8_t)(motor3 & 0xFF);
      raw_tx.tx_data[6] = (uint8_t)((motor4 >> 8) & 0xFF);
      raw_tx.tx_data[7] = (uint8_t)(motor4 & 0xFF);

      HAL_CAN_AddTxMessage(BSP_CAN_GetHandle(can->param->chassis6020),
                           &raw_tx.tx_header, raw_tx.tx_data,
                           &(can->mailbox.up_6020 ));
      break;
		case CAN_MOTOR_3508:
      motor1 = 
          (int16_t)(output->motor3508.named.m1);
      motor2 = 
          (int16_t)(output->motor3508.named.m2);
      motor3 = 
          (int16_t)(output->motor3508.named.m3);
      motor4 = 
          (int16_t)(output->motor3508.named.m4);

      raw_tx.tx_header.StdId =CAN_G3508_CTRL_ALL_ID;
      raw_tx.tx_header.IDE = CAN_ID_STD;
      raw_tx.tx_header.RTR = CAN_RTR_DATA;
      raw_tx.tx_header.DLC = CAN_MOTOR_TX_BUF_SIZE;

      raw_tx.tx_data[0] = (uint8_t)((motor1 >> 8) & 0xFF);
      raw_tx.tx_data[1] = (uint8_t)(motor1 & 0xFF);
      raw_tx.tx_data[2] = (uint8_t)((motor2 >> 8) & 0xFF);
      raw_tx.tx_data[3] = (uint8_t)(motor2 & 0xFF);
      raw_tx.tx_data[4] = (uint8_t)((motor3 >> 8) & 0xFF);
      raw_tx.tx_data[5] = (uint8_t)(motor3 & 0xFF);
      raw_tx.tx_data[6] = (uint8_t)((motor4 >> 8) & 0xFF);
      raw_tx.tx_data[7] = (uint8_t)(motor4 & 0xFF);

      HAL_CAN_AddTxMessage(BSP_CAN_GetHandle(can->param->motor3508),
                           &raw_tx.tx_header, raw_tx.tx_data,
                           &(can->mailbox.up_3508 ));
			break;
		case CAN_MOTOR_PITCH6020:
			 motor5 = 
          (int16_t)(output->pitch6020.named.m1);
		  raw_tx.tx_header.StdId = CAN_PITCH6020_CTRL_ID;
      raw_tx.tx_header.IDE = CAN_ID_STD;
      raw_tx.tx_header.RTR = CAN_RTR_DATA;
      raw_tx.tx_header.DLC = CAN_MOTOR_TX_BUF_SIZE;
		  
		  raw_tx.tx_data[0] = (uint8_t)((motor5 >> 8) & 0xFF);
      raw_tx.tx_data[1] = (uint8_t)(motor5 & 0xFF);
      raw_tx.tx_data[2] = 0;
      raw_tx.tx_data[3] = 0;
      raw_tx.tx_data[4] = 0;
      raw_tx.tx_data[5] = 0;
      raw_tx.tx_data[6] = 0;
      raw_tx.tx_data[7] = 0;
		
     HAL_CAN_AddTxMessage(BSP_CAN_GetHandle(can->param->pitch6020),
                           &raw_tx.tx_header, raw_tx.tx_data,
                           &(can->mailbox.up_6020 ));
		  break;
    
    default:
      break;
  }
  return DEVICE_OK;
}
												 
//用来问答接收来自sick的数据
void CAN_Sick_Control(CAN_t *can)
{
	raw_tx.tx_header.StdId = 0x301;
	raw_tx.tx_header.IDE = CAN_ID_STD;
	raw_tx.tx_header.DLC = 0x08;
	raw_tx.tx_header.RTR = CAN_RTR_DATA;//˽ߝ֡
	raw_tx.tx_data[0] = 0x00;
	raw_tx.tx_data[1] = 0x00;
	raw_tx.tx_data[2] = 0x00;
	raw_tx.tx_data[3] = 0x00;
	raw_tx.tx_data[4] = 0x00;
	raw_tx.tx_data[5] = 0x00;
	raw_tx.tx_data[6] = 0x00;
	raw_tx.tx_data[7] = 0x00;
	
	HAL_CAN_AddTxMessage(BSP_CAN_GetHandle(can->param->sick),&raw_tx.tx_header,raw_tx.tx_data,&(can->mailbox.up_other ));
}	

int8_t CAN_VESC_Control(int id,CAN_MotorGroup_e group, CAN_Output_t *output,CAN_t *can){
    if (output == NULL) return DEVICE_ERR_NULL;
    int Byte[4];
   Vesc_ByteGet raw[4];
    switch (group) {
     case CAN_MOTOR_CHASSIS5065:
			 //将期望的四个电机输出值分别对应到四个联合体 为了下面的拆分字节
			raw[0].as_array = output->chassis5065.named.m1;
		  raw[1].as_array = output->chassis5065.named.m2;
		  raw[2].as_array = output->chassis5065.named.m3;
		  raw[3].as_array = output->chassis5065.named.m4;
		 
     for(int i=0 ; i < 4 ; i ++)
     {			 
			 if(i==2)  //此处可能同时发送四个vesc导致只有三个轮子接收到数据 故加上delay
			 {
				osDelay(1);
			 }
			 //将单个电机的期望输出值通过联合体拆分
      Byte[0] = raw[i].byte.byte1;
      Byte[1] = raw[i].byte.byte2;
			Byte[2] = raw[i].byte.byte3;
			Byte[3] = raw[i].byte.byte4;
			 
      raw_tx.tx_header.ExtId = id+i+CAN_VESC_CTRL_ID_BASE;
      raw_tx.tx_header.IDE = CAN_ID_EXT;
      raw_tx.tx_header.RTR = CAN_RTR_DATA;
      raw_tx.tx_header.DLC = CAN_MOTOR_TX_BUF_SIZE;

      raw_tx.tx_data[0] = Byte[3];
      raw_tx.tx_data[1] = Byte[2];
      raw_tx.tx_data[2] = Byte[1];
      raw_tx.tx_data[3] = Byte[0];
      raw_tx.tx_data[4] = 0;
      raw_tx.tx_data[5] = 0;
      raw_tx.tx_data[6] = 0;
      raw_tx.tx_data[7] = 0;

      HAL_CAN_AddTxMessage(BSP_CAN_GetHandle(can->param->chassis5065),
                           &raw_tx.tx_header, raw_tx.tx_data,
                           &(can->mailbox.up_5065 ));
     }
    }
  return DEVICE_OK;
}
/**
 * @brief 将接收到的CAN消息存储在CAN_t结构体中，对容易有id冲突的进行can1和can2分类
 * @param can 要存储消息的CAN_t结构体
 * @param can_rx 接收到的CAN消息
 * @return 如果消息存储成功，DEVICE_ERR_NULL 如果can或can_rx为NULL
 */
int8_t CAN_StoreMsg(CAN_t *can, CAN_RawRx_t *can_rx) {
  // 检查输入参数是否为空
  if (can == NULL) return DEVICE_ERR_NULL;
  if (can_rx == NULL) return DEVICE_ERR_NULL;

  uint32_t index;

  // 处理CAN1消息
  if (can_rx->hcan == BSP_CAN_GetHandle(BSP_CAN_1)) {
    switch (can_rx->rx_header.StdId) {
      case CAN_G6020_AgvM1:
      case CAN_G6020_AgvM2:
      case CAN_G6020_AgvM3:
      case CAN_G6020_AgvM4:
        // 存储消息到对应的电机结构体中
        index = can_rx->rx_header.StdId - CAN_G6020_AgvM1;
        can->recive_flag |= 1 << (index);
        CAN_DJIMotor_Decode(&(can->motor.chassis6020.as_array[index]), can_rx->rx_data);
        break;

      case CAN_M3508_M1_ID:
      case CAN_M3508_M2_ID:
      case CAN_M3508_M3_ID:
      case CAN_M3508_M4_ID:
        // 存储消息到对应的电机结构体中
        index = can_rx->rx_header.StdId - CAN_M3508_M1_ID;
        can->recive_flag |= 1 << (index);
        CAN_DJIMotor_Decode(&(can->motor.motor3508.as_array[index]), can_rx->rx_data);
        break;

      default:
        break;
    }
  }

  // 处理CAN2消息
  if (can_rx->hcan == BSP_CAN_GetHandle(BSP_CAN_2)) {
    switch (can_rx->rx_header.StdId) {
      case CAN_G6020_Pitch:
        // 存储消息到对应的电机结构体中
        index = can_rx->rx_header.StdId - CAN_G6020_Pitch;
        can->recive_flag |= 1 << (index);
        CAN_DJIMotor_Decode(&(can->motor.pit6020.as_array[index]), can_rx->rx_data);
        break;
        case CAN_SICK_ID:
         // 存储消息到sickfed结构体中
         CAN_Sick_Receive(&(can->sickfed), can_rx->rx_data);
        break;

      default:
        break;
    }
  }

  // 处理扩展ID消息
  switch (can_rx->rx_header.ExtId) {
		
    case CAN_VESC5065_M1_MSG1:
      // 存储消息到对应的电机结构体中
      CAN_VescMotor_Decode_1(&(can->motor.chassis5065.as_array[0]), can_rx->rx_data);
      break;

    case CAN_VESC5065_M2_MSG1:
      // 存储消息到对应的电机结构体中
      CAN_VescMotor_Decode_1(&(can->motor.chassis5065.as_array[1]), can_rx->rx_data);
      break;

//    case CAN_VESC5065_M3_MSG1:
//      // 存储消息到对应的电机结构体中
//      CAN_VescMotor_Decode_1(&(can->motor.chassis5065.as_array[2]), can_rx->rx_data);
//      break;

//    case CAN_VSEC5065_M4_MSG1:
//      // 存储消息到对应的电机结构体中
//      CAN_VescMotor_Decode_1(&(can->motor.chassis5065.as_array[3]), can_rx->rx_data);
      break;



    default:
      break;
  }

  return DEVICE_OK;
}	
bool_t CAN_CheckFlag(CAN_t *can, uint32_t flag) {
  if (can == NULL) return false;
  return (can->recive_flag & flag) == flag;
}

int8_t CAN_ClearFlag(CAN_t *can, uint32_t flag) {
  if (can == NULL) return DEVICE_ERR_NULL;
  can->recive_flag &= ~flag;
  return DEVICE_OK;
}
