Commit bc64753f authored by 时海鑫's avatar 时海鑫

Merge branch 'dev' into 'master'

first commit

See merge request !4
parents d259d72c bd839d7d
This diff is collapsed.
#ifndef _BACKLIGHT_H_
#define _BACKLIGHT_H_
#include "common.h"
#include "Components.h"
#ifdef Platform_16Bit
#define Light_uint8_t unsigned char
#define Light_uint16_t unsigned int
#define Light_uint32_t unsigned long
#else
#define Light_uint8_t unsigned char
#define Light_uint16_t unsigned short
#define Light_uint32_t unsigned int
#define Light_uint64_t unsigned long long
#endif
#ifndef Backlight_NULL
#define Backlight_NULL ( void * )0u
#endif /* NULL */
/*光感数据存储结构体*/
typedef struct
{
uint32_t u32Result;
uint8_t u8DayandNightSts;
}Backlight_User_OPT3004_st_t;
extern Backlight_User_OPT3004_st_t opt3004;
void Backlight_KL30_Wakeup_Init(void);
void Backlight_SetPwm_cotrol(void);
void ADProcess_NTC_Temp_Service(void);
void Luminous_Time_Alter(uint16_t Val);
void Luminous_Value_Pwm_Alter(uint16_t Val);
uint16_t Get_Luminous_Value_Pwm(void);
uint16_t Get_Luminous_Value_recovery(void);
#endif
#include "Battery_Voltage.h"
#include "Components.h"
BatteryVoltage BatteryVoltageCtrl;
uint16_t Digital_Voltage = 0u;
uint16_t DigitalVoltage_Timer = 0u;
/******************************************************************************
函数名:Duty_Cycle_Delta
�? 能:阻尼处理
�? 数:�?
返回值:�?
******************************************************************************/
void Duty_Cycle_Delta(uint16_t Goal, uint16_t *Current, uint16_t *DampingTimer)
{
uint16_t Delta = 0;
uint16_t Delta1 = 0;
if ( Goal > (*Current) ) //�?标值大于当前�?
{
Delta = Goal - (*Current);
Delta1 = Goal - (*Current);
(*DampingTimer)++;
if ( (*DampingTimer) >= 5 )
{
(*DampingTimer) = 0;
Delta /= 10;
if ( Delta == 0 )
{
Delta = 1;
}
if ( (*Current) < Goal )
{
(*Current) += Delta;
}
if ( (*Current) > Goal )
{
(*Current) = Goal;
(*DampingTimer) = 0;
}
}
}
else if ( Goal < (*Current) ) //�?标值小于当前�?
{
Delta = (*Current) - Goal;
(*DampingTimer)++;
if ( (*DampingTimer) >= 5 )
{
(*DampingTimer) = 0;
Delta /= 10;
if ( Delta == 0 )
{
Delta = 1;
}
if ( (*Current) > Goal )
{
(*Current) -= Delta;
}
if ( (*Current) < Goal )
{
(*Current) = Goal;
(*DampingTimer) = 0;
}
}
}
}
void Display_Battery_Voltage(void)
{
if(DigitalVoltage_Timer >= 30)//3秒采集一次
{
DigitalVoltage_Timer = 0;
Digital_Voltage = ADC_Read_Signal(ADC_CH_KL30_VOLTAGE) / 100U;
}
else
{
DigitalVoltage_Timer++;
}
BatteryVoltageCtrl.BatteryVoltageCurrent = Digital_Voltage;
}
uint16_t Get_Battery_Voltage_Display(void) //获取电池电压表数值
{
return BatteryVoltageCtrl.BatteryVoltageCurrent;
}
\ No newline at end of file
#ifndef _BATTERY_VOLTAGE_H_
#define _BATTERY_VOLTAGE_H_
#include "common.h"
#include "Components.h"
typedef struct
{
uint16_t Goal;
uint16_t BatteryVoltageCurrent;
uint16_t Time;
} BatteryVoltage;
extern void Duty_Cycle_Delta(uint16_t Goal, uint16_t *Current, uint16_t *DampingTimer);
extern void Display_Battery_Voltage(void);
extern uint16_t Get_Battery_Voltage_Display(void); //获取电池电压表数值
#endif
\ No newline at end of file
#include "CAN_Lib.h"
#include "CAN_APP.h"
#include "CAN_APP_TX.h"
#include "CommonInterface.h"
#include "CAN_CH0_CAN_Communication_Matrix.h"
#include "Data_VSpeed.h"
#include "Components.h"
#include "CommonInterface.h"
void Data_CAN_APP_Init(void)
{
}
uint8_t CRC8_SAE_J1850(uint8_t *u8_data, uint8_t u8_len)
{
// uint8_t i, j;
uint8_t u8_crc8 = 0u;
// uint8_t u8_poly;
// u8_crc8 = 0xFF;
// u8_poly = 0x1D;
// for ( i = 0; i < u8_len; i++ )
// {
// u8_crc8 ^= u8_data [ i ];
// for ( j = 0; j < 8; j++ )
// {
// if ( u8_crc8 & 0x80 )
// {
// u8_crc8 = (( uint8_t )((u8_crc8 << 1) ^ u8_poly));
// }
// else
// {
// u8_crc8 <<= 1;
// }
// }
// }
// u8_crc8 ^= ( uint8_t )0xFF;
return u8_crc8;
}
void Can_Write_Fun_APP(void)
{
}
void Can_Abort_Confirm(uint32_t Identifier, uint8_t TransferStatus)
{
}
void Can_QuickTimer_Init(void)
{
uint32_t i = 0u;
for ( i = 0u; i < CAN_CH0_ID_SEND_TOTAL; i++ )
{
Can_Msg_TX_FastInitCycle(&CAN_CH0_CanMsgTxOp, i, CAN_CH0_CANSendAttr [ i ].u32MsgCycleOffset);
}
}
void NODE_26D_SET_Confirm(void)
{
}
void Can_BusOff_Fun(void)
{
}
void Set_CarWashModeFeedback(uint8_t status)
{
}
void Can_Set_Buff_100(uint8_t CopyData[])
{
CANMsg100Union *pCANMsg100;
uint8_t i = 0u;
uint16_t Actual = 0u;
uint16_t Actual1 = 0u;
pCANMsg100 = (CANMsg100Union *)CopyData;
Actual = (Get_ActualVechileSpeed());
Actual1 = (Get_ActualVechileSpeed());
Actual = (Actual * 18 / 10);
if(Actual1 >= 1975)
{
Actual = 3560u;
}
if (pCANMsg100 != (void *)0)
{
for (i = 0u; i < 8u; i++)
{
pCANMsg100->Msg[i] = 0u;
}
if (Common_Get_IG_Sts() == COMMON_POWER_ON)
{
if (Common_GetIgnOnTimeL() > 500)
{
pCANMsg100->Sig.IP_ABS1_N_wheelSpeed_Front_L = (uint8_t)((Actual>>5) & 0x00FF);
pCANMsg100->Sig.IP_ABS1_N_wheelSpeed_Front_H = (uint8_t)((Actual) & 0x001F);
pCANMsg100->Sig.IP_ABS1_N_wheelSpeed_Rear_L = (uint8_t)((Actual>>11) & 0x0003);
pCANMsg100->Sig.IP_ABS1_N_wheelSpeed_Rear_M = (uint8_t)((Actual>>3) & 0x00FF);
pCANMsg100->Sig.IP_ABS1_N_wheelSpeed_Rear_H = (uint8_t)((Actual) & 0x0007);
}
else
{
pCANMsg100->Sig.IP_ABS1_N_wheelSpeed_Front_L = (0x00FF);
pCANMsg100->Sig.IP_ABS1_N_wheelSpeed_Front_H = (0x001F);
pCANMsg100->Sig.IP_ABS1_N_wheelSpeed_Rear_L = (0x0003);
pCANMsg100->Sig.IP_ABS1_N_wheelSpeed_Rear_M = (0x00FF);
pCANMsg100->Sig.IP_ABS1_N_wheelSpeed_Rear_H = (0x0007);
}
}
else
{
}
}
}
void Can_Set_Buff_213(uint8_t CopyData[])
{
CANMsg213Union *pCANMsg213;
uint8_t i = 0u;
uint8_t Signal1 = 0u;
uint8_t Signal2 = 0u;
uint8_t Signal3 = 0u;
uint8_t Signal4 = 0u;
uint8_t Signal5 = 0u;
uint8_t Error = 0u;
pCANMsg213 = (CANMsg213Union *)CopyData;
if (pCANMsg213 != (void *)0)
{
for (i = 0u; i < 8u; i++)
{
pCANMsg213->Msg[i] = 0u;
}
//挡位指示
Signal1 = Get_CAN_CH0_ID_402_Sig_Rear_Gear_State();
Signal2 = Get_CAN_CH0_ID_402_Sig_Low_Gear_State();
Signal3 = Get_CAN_CH0_ID_402_Sig_High_Gear_State();
Signal4 = Get_CAN_CH0_ID_400_Sig_Park_Switch();
Signal5 = Get_CAN_CH0_ID_400_Sig_Neutral_Switch();
if (CAN_RX_Get_TimeStamp(&CAN_CH0_CanMsgOp, CAN_CH0_ID_ECU_402_Msg_Count) >= 3000u)
{
Signal1 = 0u;
Signal2 = 0u;
Signal3 = 0u;
}
if (CAN_RX_Get_TimeStamp(&CAN_CH0_CanMsgOp, CAN_CH0_ID_ECU_400_Msg_Count) >= 3000u)
{
Signal4 = 0u;
Signal5 = 0u;
}
Error = (Signal1 + Signal2 + Signal3 + Signal4 + Signal5);
if (Common_Get_IG_Sts() == COMMON_POWER_ON)
{
if (Error > 1u)
{
pCANMsg213->Sig.IP_shift = 0xFF;
}
else
{
if (Common_GetIgnOnTimeL() > 500)
{
if (Signal5 == 1)
{
pCANMsg213->Sig.IP_shift = 0x00;
}
else if (Signal4 == 1)
{
pCANMsg213->Sig.IP_shift = 0x0B;
}
else if (Signal2 == 1)
{
pCANMsg213->Sig.IP_shift = 0x0C;
}
else if (Signal3 == 1)
{
pCANMsg213->Sig.IP_shift = 0x0D;
}
else if (Signal1 == 1)
{
pCANMsg213->Sig.IP_shift = 0x0A;
}
else
{
pCANMsg213->Sig.IP_shift = 0xFF;
}
}
else
{
pCANMsg213->Sig.IP_shift = 0xFF;
}
}
}
else
{
}
}
}
void Can_Set_Buff_50A(uint8_t CopyData [])
{
// uint8_t i = 0u;
// CANMsg214Union *pCANMsg50A;
// pCANMsg50A = ( CANMsg214Union * )CopyData;
// if ( pCANMsg50A != ( void * )0 )
// {
// for ( i = 0u; i < 8u; i++ )
// {
// pCANMsg50A->Msg [ i ] = 0u;
// }
// }
}
void Can_Set_Buff_530(uint8_t CopyData [])
{
// uint8_t i = 0u;
// CANMsg530Union *pCANMsg530;
// pCANMsg530 = ( CANMsg530Union * )CopyData;
// if ( pCANMsg530 != ( void * )0 )
// {
// for ( i = 0u; i < 8u; i++ )
// {
// pCANMsg530->Msg [ i ] = 0u;
// }
// }
}
void Can_Set_Buff_385(uint8_t CopyData [])
{
uint8_t i = 0u;
CANMsg385Union *pCANMsg385;
pCANMsg385 = ( CANMsg385Union * )CopyData;
if ( pCANMsg385 != ( void * )0 )
{
for ( i = 0u; i < 8u; i++ )
{
pCANMsg385->Msg [ i ] = 0u;
}
}
}
void Can_Set_Buff_52E(uint8_t CopyData [])
{
uint8_t i = 0u;
CANMsg52EUnion *pCANMsg52E;
pCANMsg52E = ( CANMsg52EUnion * )CopyData;
if ( pCANMsg52E != ( void * )0 )
{
for ( i = 0u; i < 8u; i++ )
{
pCANMsg52E->Msg [ i ] = 0u;
}
}
}
void Can_Set_Buff_69B(uint8_t CopyData [])
{
CANMsg69BUnion *pCANMsg69B;
pCANMsg69B = ( CANMsg69BUnion * )CopyData;
if ( pCANMsg69B != ( void * )0 )
{
}
}
void Can_Set_Buff_28A(uint8_t CopyData [])
{
uint8_t i = 0u;
CANMsg28AUnion *pCANMsg28A;
pCANMsg28A = ( CANMsg28AUnion * )CopyData;
if ( pCANMsg28A != ( void * )0 )
{
for ( i = 0u; i < 8u; i++ )
{
pCANMsg28A->Msg [ i ] = 0u;
}
}
}
void Can_Set_Buff_2DE(uint8_t CopyData [])
{
uint8_t i = 0u;
CANMsg2DEUnion *pCANMsg2DE;
pCANMsg2DE = ( CANMsg2DEUnion * )CopyData;
if ( pCANMsg2DE != ( void * )0 )
{
for ( i = 0u; i < 8u; i++ )
{
pCANMsg2DE->Msg [ i ] = 0u;
}
}
}
void Can_Set_Buff_640(uint8_t CopyData [])
{
uint8_t i = 0u;
CANMsg640Union *pCANMsg640;
pCANMsg640 = ( CANMsg640Union * )CopyData;
if ( pCANMsg640 != ( void * )0 )
{
for ( i = 0u; i < 8u; i++ )
{
pCANMsg640->Msg [ i ] = 0u;
}
}
}
void Can_Set_Buff_6F1(uint8_t CopyData [])
{
uint8_t i = 0u;
CANMsg6F1Union *pCANMsg6F1;
pCANMsg6F1 = ( CANMsg6F1Union * )CopyData;
if ( pCANMsg6F1 != ( void * )0 )
{
for ( i = 0u; i < 8u; i++ )
{
pCANMsg6F1->Msg [ i ] = 0u;
}
}
}
void Can_Set_Buff_6F2(uint8_t CopyData [])
{
uint8_t i = 0u;
CANMsg6F2Union *pCANMsg6F2;
pCANMsg6F2 = ( CANMsg6F2Union * )CopyData;
if ( pCANMsg6F2 != ( void * )0 )
{
for ( i = 0u; i < 8u; i++ )
{
pCANMsg6F2->Msg [ i ] = 0u;
}
}
}
void Can_Set_Buff_6F3(uint8_t CopyData [])
{
uint8_t i = 0u;
CANMsg6F3Union *pCANMsg6F3;
pCANMsg6F3 = ( CANMsg6F3Union * )CopyData;
if ( pCANMsg6F3 != ( void * )0 )
{
for ( i = 0u; i < 8u; i++ )
{
pCANMsg6F3->Msg [ i ] = 0u;
}
}
}
void Can_Set_Buff_6F5(uint8_t CopyData [])
{
uint8_t i = 0u;
CANMsg6F5Union *pCANMsg6F5;
pCANMsg6F5 = ( CANMsg6F5Union * )CopyData;
if ( pCANMsg6F5 != ( void * )0 )
{
for ( i = 0u; i < 8u; i++ )
{
pCANMsg6F5->Msg [ i ] = 0u;
}
}
}
void Can_Set_Buff_6F7(uint8_t CopyData [])
{
uint8_t i = 0u;
CANMsg6F7Union *pCANMsg6F7;
pCANMsg6F7 = ( CANMsg6F7Union * )CopyData;
if ( pCANMsg6F7 != ( void * )0 )
{
for ( i = 0u; i < 8u; i++ )
{
pCANMsg6F7->Msg [ i ] = 0u;
}
}
}
#ifndef _CAN_APP_H_
#define _CAN_APP_H_
#include "Components.h"
void Can_Abort_All(void);
void Can_QuickTimer_Init(void);
void Can_Write_Fun_APP(void);
void Can_BusOff_Fun(void);
void Data_CAN_APP_Init(void);
void Can_Set_Buff_100(uint8_t CopyData[]);
void Can_Set_Buff_213(uint8_t CopyData[]);
/*void Can_Set_Buff_260(uint8_t CopyData []);*/
void Can_Set_Buff_0CFE6C17(uint8_t CopyData []);
void Can_Set_Buff_50A(uint8_t CopyData []);
void Can_Set_Buff_530(uint8_t CopyData []);
void Can_Set_Buff_385(uint8_t CopyData []);
void Can_Set_Buff_52E(uint8_t CopyData []);
void Can_Set_Buff_69B(uint8_t CopyData []);
void Can_Set_Buff_28A(uint8_t CopyData []);
void Can_Set_Buff_2DE(uint8_t CopyData []);
void Can_Set_Buff_640(uint8_t CopyData []);
void Can_Set_Buff_6F1(uint8_t CopyData []);
void Can_Set_Buff_6F2(uint8_t CopyData []);
void Can_Set_Buff_6F3(uint8_t CopyData []);
void Can_Set_Buff_6F5(uint8_t CopyData []);
void Can_Set_Buff_6F7(uint8_t CopyData []);
void CAN_ID_326_CountClear(void);
void CAN_ID_295_CountClear(void);
void CAN_ID_326_Count(void);
void CAN_ID_295_Count(void);
void CAN_MSG_COUNTER_PLUS(void);
uint8_t CRC8_SAE_J1850(uint8_t *u8_data, uint8_t u8_len);
void Set_CarWashModeFeedback(uint8_t status);
void Set_ShortTermClrFlg(uint8_t Flag);
void Set_LongTermClrFlg(uint8_t Flag);
void Set_RefuelEndClrFlg(uint8_t Flag);
void Set_WholeTermClrFlg(uint8_t Flag);
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#include "Can_User.h"
#include <string.h>
#include "can.h"
#include "RTE.h"
#include "CAN_CH0_CAN_Communication_Matrix.h"
#include "DoCAN_ISO15765.h"
__align(4)
uint32_t pRXBuff[CAN_RX_MSG_Block * CAN_CH0_ID_TOTAL_MAX];
uint32_t pTXBuff[CAN_TX_MSG_Block * CAN_CH0_ID_SEND_TOTAL];
static RSCAN0BusoffMonitorStruct RSCAN0Busoff;
void Can_Init(void)
{
can_config_st_t Can_Config;
Can_Config.ch = CAN_CH_0;
Can_Config.freq = CAN_500Kbps;
Can_Config.MASK[0] = 0x1fffffffU;
Can_Config.MASK[1] = 0x1fffffffU;
Can_Config.MASK[2] = 0x1fffffffU;
Can_Config.MASK[3] = 0x1fffffffU;
Can_Config.rx_callback = Can_Rx_Cak;
COM_CAN_Init();
rte_can_init(&Can_Config);
Can_Tx_Apply_Buff();
Can_RX_Apply_Buff();
RTE_GPIO_Set_Level(RTE_GPIO_PORT05_PIN02,RTE_GPIO_LEVEL_LOW);
}
/**
* @brief 用于申请RXBUFF CAN0MSG01~CAN0MSG011
*
*/
void Can_RX_Apply_Buff(void)
{
// CAN_RecvMsg.Id = 0x213ul;
// CAN_RecvMsg.IDE = CAN_Id_Standard;
// CAN_RecvMsg.CacheType = CAN_CacheType_Rx_NoMask;
// CAN_RecvMsg.RTR = CAN_RTR_Data;
// CAN_RecvMsg.Interrupt = ENABLE;
// CAN_MessageCache_DeInit(CAN0MSG07);
// CAN_MessageCache_Init(CAN0MSG07, &CAN_RecvMsg);
// CAN_MessageCache_OverWriteConfig(CAN0MSG07, ENABLE);
CAN_RecvMsg.Id = 0x404;
CAN_RecvMsg.IDE = CAN_Id_Standard;
CAN_RecvMsg.CacheType = CAN_CacheType_Rx_NoMask;
CAN_RecvMsg.RTR = CAN_RTR_Data;
CAN_RecvMsg.Interrupt = ENABLE;
CAN_MessageCache_DeInit(CAN0MSG06);
CAN_MessageCache_Init(CAN0MSG06, &CAN_RecvMsg);
CAN_MessageCache_OverWriteConfig(CAN0MSG06, ENABLE);
CAN_RecvMsg.Id = 0x5FAul;
CAN_RecvMsg.IDE = CAN_Id_Standard;
CAN_RecvMsg.CacheType = CAN_CacheType_Rx_NoMask;
CAN_RecvMsg.RTR = CAN_RTR_Data;
CAN_RecvMsg.Interrupt = ENABLE;
CAN_MessageCache_DeInit(CAN0MSG01);
CAN_MessageCache_Init(CAN0MSG01, &CAN_RecvMsg);
CAN_MessageCache_OverWriteConfig(CAN0MSG01, ENABLE);
CAN_RecvMsg.Id = 0x402;
CAN_RecvMsg.IDE = CAN_Id_Standard;
CAN_RecvMsg.CacheType = CAN_CacheType_Rx_NoMask;
CAN_RecvMsg.RTR = CAN_RTR_Data;
CAN_RecvMsg.Interrupt = ENABLE;
CAN_MessageCache_DeInit(CAN0MSG04);
CAN_MessageCache_Init(CAN0MSG04, &CAN_RecvMsg);
CAN_MessageCache_OverWriteConfig(CAN0MSG04, ENABLE);
CAN_RecvMsg.Id = 0x401;
CAN_RecvMsg.IDE = CAN_Id_Standard;
CAN_RecvMsg.CacheType = CAN_CacheType_Rx_NoMask;
CAN_RecvMsg.RTR = CAN_RTR_Data;
CAN_RecvMsg.Interrupt = ENABLE;
CAN_MessageCache_DeInit(CAN0MSG03);
CAN_MessageCache_Init(CAN0MSG03, &CAN_RecvMsg);
CAN_MessageCache_OverWriteConfig(CAN0MSG03, ENABLE);
CAN_RecvMsg.Id = 0x400;
CAN_RecvMsg.IDE = CAN_Id_Standard;
CAN_RecvMsg.CacheType = CAN_CacheType_Rx_NoMask;
CAN_RecvMsg.RTR = CAN_RTR_Data;
CAN_RecvMsg.Interrupt = ENABLE;
CAN_MessageCache_DeInit(CAN0MSG02);
CAN_MessageCache_Init(CAN0MSG02, &CAN_RecvMsg);
CAN_MessageCache_OverWriteConfig(CAN0MSG02, ENABLE);
CAN_RecvMsg.Id = 0x101;
CAN_RecvMsg.IDE = CAN_Id_Standard;
CAN_RecvMsg.CacheType = CAN_CacheType_Rx_NoMask;
CAN_RecvMsg.RTR = CAN_RTR_Data;
CAN_RecvMsg.Interrupt = ENABLE;
CAN_MessageCache_DeInit(CAN0MSG11);
CAN_MessageCache_Init(CAN0MSG11, &CAN_RecvMsg);
CAN_MessageCache_OverWriteConfig(CAN0MSG11, ENABLE);
// CAN_RecvMsg.Id = 0x100;
// CAN_RecvMsg.IDE = CAN_Id_Standard;
// CAN_RecvMsg.CacheType = CAN_CacheType_Rx_NoMask;
// CAN_RecvMsg.RTR = CAN_RTR_Data;
// CAN_RecvMsg.Interrupt = ENABLE;
// CAN_MessageCache_DeInit(CAN0MSG10);
// CAN_MessageCache_Init(CAN0MSG10, &CAN_RecvMsg);
// CAN_MessageCache_OverWriteConfig(CAN0MSG10, ENABLE);
CAN_RecvMsg.Id = 0x12B;
CAN_RecvMsg.IDE = CAN_Id_Standard;
CAN_RecvMsg.CacheType = CAN_CacheType_Rx_NoMask;
CAN_RecvMsg.RTR = CAN_RTR_Data;
CAN_RecvMsg.Interrupt = ENABLE;
CAN_MessageCache_DeInit(CAN0MSG05);
CAN_MessageCache_Init(CAN0MSG05, &CAN_RecvMsg);
CAN_MessageCache_OverWriteConfig(CAN0MSG05, ENABLE);
CAN_RecvMsg.Id = DIAG_ID_Rx_PHY;
CAN_RecvMsg.IDE = CAN_Id_Standard;
CAN_RecvMsg.CacheType = CAN_CacheType_Rx_NoMask;
CAN_RecvMsg.RTR = CAN_RTR_Data;
CAN_RecvMsg.Interrupt = ENABLE;
CAN_MessageCache_DeInit(CAN0MSG08);
CAN_MessageCache_Init(CAN0MSG08, &CAN_RecvMsg);
CAN_MessageCache_OverWriteConfig(CAN0MSG08, ENABLE);
CAN_RecvMsg.Id = DIAG_ID_Rx_FUN;
CAN_RecvMsg.IDE = CAN_Id_Standard;
CAN_RecvMsg.CacheType = CAN_CacheType_Rx_NoMask;
CAN_RecvMsg.RTR = CAN_RTR_Data;
CAN_RecvMsg.Interrupt = ENABLE;
CAN_MessageCache_DeInit(CAN0MSG09);
CAN_MessageCache_Init(CAN0MSG09, &CAN_RecvMsg);
CAN_MessageCache_OverWriteConfig(CAN0MSG09, ENABLE);
}
/**
* @brief 用于申请TXBUFF
*
*/
void Can_Tx_Apply_Buff(void)
{
CanTxRxMsg CAN_SendMsg;
CanTxRxMsg CAN_SendMsg_Diag_Tx;
CAN_SendMsg.Id = 0x213ul;
CAN_SendMsg.IDE = CAN_Id_Standard;
CAN_SendMsg.CacheType = CAN_CacheType_Tx;
CAN_SendMsg.RTR = CAN_RTR_Data;
CAN_RecvMsg.Interrupt = ENABLE;
CAN_SendMsg.DLC = 8;
for (uint8_t i = 0; i < CAN_SendMsg.DLC; i++)
{
CAN_SendMsg.Data[i] = 0;
}
CAN_MessageCache_DeInit(CAN0MSG07);
CAN_MessageCache_Init(CAN0MSG07, &CAN_SendMsg);
CAN_SendMsg.Id = 0x100ul;
CAN_SendMsg.IDE = CAN_Id_Standard;
CAN_SendMsg.CacheType = CAN_CacheType_Tx;
CAN_SendMsg.RTR = CAN_RTR_Data;
CAN_RecvMsg.Interrupt = ENABLE;
CAN_SendMsg.DLC = 8;
for (uint8_t i = 0; i < CAN_SendMsg.DLC; i++)
{
CAN_SendMsg.Data[i] = 0;
}
CAN_MessageCache_DeInit(CAN0MSG10);
CAN_MessageCache_Init(CAN0MSG10, &CAN_SendMsg);
CAN_SendMsg_Diag_Tx.Id = DIAG_ID_Tx;
CAN_SendMsg_Diag_Tx.IDE = CAN_Id_Standard;
CAN_SendMsg_Diag_Tx.CacheType = CAN_CacheType_Tx;
CAN_SendMsg_Diag_Tx.RTR = CAN_RTR_Data;
CAN_SendMsg_Diag_Tx.Interrupt = DISABLE;
CAN_SendMsg_Diag_Tx.DLC = 8;
for (uint8_t i = 0; i < CAN_SendMsg_Diag_Tx.DLC; i++)
{
CAN_SendMsg_Diag_Tx.Data[i] = 0;
}
CAN_MessageCache_DeInit(CAN0MSG00);
CAN_MessageCache_Init(CAN0MSG00, &CAN_SendMsg_Diag_Tx);
}
/**
* @brief 用于接收回调函数
* @code
*/
void Can_Rx_Cak(CanTxRxMsg *Msg)
{
Co_Can_Buff_Set(&CAN_CH0_CanMsgOp, Co_Can_ConvertSubID_CAN_CH0(Msg->Id), Msg->DLC, Msg->Data);
if ((Msg->Id == DIAG_ID_Rx_FUN) || (Msg->Id == DIAG_ID_Rx_PHY))
{
DoCAN_L_Data_Indication((uint16_t)Msg->Id, Msg->DLC, Msg->Data);
}
}
/**
* @brief CAN库初始化TX/RX
*
*/
void COM_CAN_Init(void)
{
memset(pRXBuff, 0, sizeof(pRXBuff));
CAN_CH0_CanMsgOp.CAN_MSG_Analysis = (st_CANMsgStruct *)pRXBuff;
CAN_CH0_CanMsgOp.pAttrubute = CAN_CH0_CAN_MSG_CONST_ARRAY;
CAN_CH0_CanMsgOp.Total_Msg = CAN_CH0_ID_TOTAL_MAX;
CAN_CH0_CanMsgOp.u8CAN_RX_ENABLE = CAN_N_RX_Enable;
Can_RX_BuffInit(&CAN_CH0_CanMsgOp, CAN_CH0_CAN_MSG_CONST_ARRAY, CAN_CH0_ID_TOTAL_MAX);
CAN_RX_SetEnable(&CAN_CH0_CanMsgOp, CAN_N_RX_Enable);
memset(pTXBuff, 0, sizeof(pTXBuff));
CAN_CH0_CanMsgTxOp.CanMsg = (st_CAN_SendOperation *)pTXBuff;
Can_TX_BuffInit(&CAN_CH0_CanMsgTxOp, CAN_CH0_CANSendAttr, CAN_CH0_ID_SEND_TOTAL, COM_APP_Process);
CAN_TX_SetEnable(&CAN_CH0_CanMsgTxOp, CAN_N_TX_Enable);
}
uint16_t cji_canflsg = 0u;
/**
* @brief Buff恢复函数
* @param deltaTime 调用时间 单位ms 10MS调用
*/
void Can_BusOff_Recover(uint8_t deltaTime)
{
if (get_can_busoff(CAN_CH_0) == 2)
{
cji_canflsg = 1u;
if (RSCAN0Busoff.Status == RSCAN0_BUS_STABLE)
{
RSCAN0Busoff.Status = RSCAN0_BUS_OFF_LV1;
}
if (RSCAN0Busoff.Status == RSCAN0_BUS_OFF_LV1)
{
RSCAN0Busoff.Timer++;
if (RSCAN0Busoff.Timer >= RSCAN0_BUS_OFF_LV1_RECOVERY_TIME / deltaTime)
{
RSCAN0Busoff.Timer = 0U;
RSCAN0Busoff.Cnt++;
if (RSCAN0Busoff.Cnt >= 10U)
{
RSCAN0Busoff.Cnt = 0U;
RSCAN0Busoff.Status = RSCAN0_BUS_OFF_LV2;
}
reset_busoff(CAN_CH_0);
}
}
else if (RSCAN0Busoff.Status == RSCAN0_BUS_OFF_LV2)
{
RSCAN0Busoff.Timer++;
if (RSCAN0Busoff.Timer >= RSCAN0_BUS_OFF_LV2_RECOVERY_TIME / deltaTime)
{
RSCAN0Busoff.Timer = 0U;
reset_busoff(CAN_CH_0);
}
}
else
{
}
}
else /* 总线正常,没有Bus-off发生*/
{
if (cji_canflsg == 1)
{
cji_canflsg = 0u;
Can_RX_Apply_Buff();
Can_Tx_Apply_Buff();
}
}
}
/**
* @brief 获取busoff状态
* @return 0 没有busoff
* 1 错误的操作
* 2 busoff
*/
uint8_t Get_Busoff_Status(void)
{
return get_can_busoff(CAN_CH_0);
}
uint8_t COM_APP_Process(st_CAN_Msg *Msg)
{
Can_Write_((st_CAN_Msg *)Msg);
return 0;
}
void Can_Write_(st_CAN_Msg *Msg)
{
uint32_t i = 0;
CanTxRxMsg CAN_SendMsg;
CAN_SendMsg.Id = Msg->MsgID; /* ID */
CAN_SendMsg.DLC = Msg->MsgDLC; /* Len */
CAN_SendMsg.RTR = Msg->MsgRTR; /* Default 0 */
CAN_SendMsg.IDE = CAN_Id_Standard; /* Stand 0 Ext 1 */
CAN_SendMsg.CacheType = CAN_CacheType_Tx;
for (i = 0; i < CAN_SendMsg.DLC; i++) /* 获取数据 */
{
CAN_SendMsg.Data[i] = Msg->Msg[i];
}
switch (CAN_SendMsg.Id)
{
case 0x213:
CAN_Transmit(CAN0MSG07, &CAN_SendMsg);
break;
case 0x100:
CAN_Transmit(CAN0MSG10, &CAN_SendMsg);
break;
default:
break;
}
}
#ifndef _CAN_USER_H_
#define _CAN_USER_H_
#include "RTE.h"
#include "Components.h"
/******************************************************************************
Bus-off
******************************************************************************/
#define RSCAN0_BUS_STABLE 0x00U
#define RSCAN0_BUS_OFF_LV1 0x01U
#define RSCAN0_BUS_OFF_LV2 0x02U
#define RSCAN00_BUS_LIMP 0x03U
/******************************************************************************
Bus-off
******************************************************************************/
#define RSCAN0_BUS_OFF_LV1_RECOVERY_TIME 70U
#define RSCAN0_BUS_OFF_LV2_RECOVERY_TIME 1000U
typedef struct
{
uint8_t Status;
uint8_t Timer;
uint8_t Cnt;
uint8_t ReportDTCCnt;
} RSCAN0BusoffMonitorStruct;
extern void Can_Tx_Apply_Buff(void);
extern void Can_RX_Apply_Buff(void);
extern void Can_BusOff_Recover(uint8_t deltaTime);
extern void COM_CAN_Init(void);
extern void Can_Init(void);
extern void Can_Rx_Cak(CanTxRxMsg *Msg);
extern void Busoff(void);
extern uint8_t COM_APP_Process(st_CAN_Msg *Msg);
extern void Can_Write_(st_CAN_Msg *Msg);
#endif
#include "CommonInterface.h"
#include "Components.h"
#include "PowerManagement\PowerManag_user.h"
uint32_t PowerIgnOnTimeLine;
uint32_t PowerIgnOnTimeL = 0u;;
uint32_t PowerIgnOffTimeLine;
extern uint8_t Voltage_Anomaly;
static uint32_t PowerSocTimeLine;
static uint32_t PowerSelfTimer = 0;
static uint16_t tyre_Size_State = 0;
static COMMON_PowerStatus_t PowerSts; /*1 ON ; 0 OFF*/
static uint32_t Act_V_Speed; /*实际值,十倍的*/
static uint32_t Disp_V_Speed; /*显示值,十倍的*/
static DataValid_t PowerSts_Valid;
volatile static DataValid_t Act_V_Speed_Valid;
static DataValid_t Disp_V_Speed_Valid;
uint16_t Disp_Valid;
// static uint16_t u16SelfCheckTime;
/*每次唤醒调用*/
void Common_DataInit(void)
{
PowerSts = COMMON_POWER_UNKNOW;
Act_V_Speed = 0xffffu;
Disp_V_Speed = 0xffffu;
PowerSts_Valid = COMMON_Valid_UNKNOW;
Act_V_Speed_Valid = COMMON_Valid_UNKNOW;
Disp_V_Speed_Valid = COMMON_Valid_UNKNOW;
PowerIgnOnTimeLine = 0x0ul;
PowerIgnOnTimeL = 0u;
PowerIgnOffTimeLine = 0x0ul;
PowerSocTimeLine = 0x0ul;
}
/*以下由各个处理模块按需调用*/
/*使用数据之前,需要先判断数据是否有效,如果无效,则不可以使用*/
uint8_t Common_Get_IG_Sts(void)
{
return (uint8_t)PowerSts;
}
uint16_t Common_Get_Act_V_Speed(void)
{
return (uint16_t)Act_V_Speed;
}
uint16_t Common_Get_Disp_V_Speed(void)
{
return (uint16_t)Disp_V_Speed;
}
uint16_t Common_Get_TireSize(void)
{
return 1u;
}
void Common_Set_IG_Sts(COMMON_PowerStatus_t Val)
{
PowerSts = Val;
}
void Common_Set_Act_V_Speed(uint32_t Val)
{
if (Val >= 500u)
{
Val += 20u;
}
else if(Val >= 100)
{
Val += 10u;
}
Act_V_Speed = Val;
}
void Common_Set_Disp_V_Speed(uint32_t Val)
{
Disp_V_Speed = Val;
}
DataValid_t Common_Get_IG_Sts_Valid(void)
{
return PowerSts_Valid;
}
DataValid_t Common_Get_Act_V_Speed_Valid(void)
{
return Act_V_Speed_Valid;
}
DataValid_t Common_Get_Disp_V_Speed_Valid(void)
{
return Disp_V_Speed_Valid;
}
void Common_Set_IG_Sts_Valid(DataValid_t Val)
{
PowerSts_Valid = Val;
}
void Common_Set_Act_V_Speed_Valid(DataValid_t Val)
{
Act_V_Speed_Valid = Val;
}
void Common_Set_Disp_V_Speed_Valid(DataValid_t Val)
{
Disp_V_Speed_Valid = Val;
}
uint16_t Common_Get_DispSpeed(void)
{
uint16_t m_Res = 0;
return m_Res;
}
void Common_Input_Para(void)
{
if (SYS_OPR_STAT_IGN_ON)
{
Common_Set_IG_Sts(COMMON_POWER_ON);
Common_Set_IG_Sts_Valid(COMMON_Valid);
if (Get_Voltage_Anomaly() == 1)//过压无自检
{
Voltage_Anomaly = 2u;
PowerSelfTimer = 1041u;
PowerIgnOnTimeLine = 2082u;
}
if (Get_Uptime_Staus() == 1u)//开机动画结束标志位
{
if (GetLcdInitSt() == 1u)
{
PowerSelfTimer++;
if (PowerSelfTimer >= 2000u)//防止时间溢出
{
PowerSelfTimer = 2000u;
}
}
if (PowerSelfTimer > 1030u)//自检2s
{
Disp_Valid = 0u;//非自检
}
else
{
Disp_Valid = 1u;//自检
}
}
Common_Set_Act_V_Speed(Get_ActualVechileSpeed());
Common_Set_Disp_V_Speed(Get_DispVechileSpeed());
if (Get_VechileSpeedValid() == COMMON_Valid)
{
Common_Set_Act_V_Speed_Valid(COMMON_Valid);
Common_Set_Disp_V_Speed_Valid(COMMON_Valid);
}
else
{
Common_Set_Act_V_Speed_Valid(COMMON_InValid);
Common_Set_Disp_V_Speed_Valid(COMMON_InValid);
}
PowerIgnOffTimeLine = 0u;//上15电置0
if (Get_Dis_Old_Staus() == 3u)//轮胎选择界面
{
PowerSelfTimer = 0u;
PowerIgnOnTimeLine = 0u;
for(uint8_t i = 0; i<23;i++)//点亮所有指示灯
{
Telltales_DiagCtrl(i,0x01);
}
tyre_Size_State = 1u;//轮胎选择界面结束标志位
}
else
{
if (tyre_Size_State == 1u)
{
tyre_Size_State = 0u;
Telltales_DiagRelease(1);
}
if (GetLcdInitSt() >= 1u)
{
if (Get_Uptime_Staus() == 1u)
{
if (PowerIgnOnTimeLine < 0x7ffffffful)
{
PowerIgnOnTimeLine += 2u;
}
}
}
}
PowerIgnOnTimeL += 2u;
}
else
{
Disp_Valid = 0u;
PowerSelfTimer = 0u;
PowerIgnOnTimeLine = 0ul;
PowerIgnOnTimeL = 0u;
if (PowerIgnOffTimeLine < 0x7ffffffful)
{
PowerIgnOffTimeLine += 2u;
}
Common_Set_IG_Sts(COMMON_POWER_OFF);
Common_Set_IG_Sts_Valid(COMMON_Valid);
/*车转真实值OFF为0*/
Common_Set_Act_V_Speed(0u);
Common_Set_Disp_V_Speed(0u);
}
}
uint32_t Common_GetIgnOnTime(void)
{
return PowerIgnOnTimeLine;
}
uint32_t Common_GetIgnOnTimeL(void)
{
return PowerIgnOnTimeL;
}
uint32_t Common_GetIgnOffTime(void)
{
return PowerIgnOffTimeLine;
}
uint32_t Common_GetSocTime(void)
{
return PowerSocTimeLine;
}
uint16_t Get_Self(void)
{
return Disp_Valid;
}
/**
* @brief 公里转换英里
* @return 公里
*/
uint32_t Data_Km_To_Mile(uint32_t Km)
{
//Km *= 621;
//Km /= 1000;
Km *= 64;
Km /= 103;
return Km;
}
/**
* @brief 英里转换公里
* @return 英里
*/
uint32_t Data_Mile_To_Km(uint32_t Mile)
{
Mile *= 103;
Mile /= 64;
return Mile;
}
void Data_SwapWord(uint32_t *pData1, uint32_t *pData2)
{
uint32_t psw;
if ((*pData1) > (*pData2))
{
psw = (*pData2);
(*pData2) = (*pData1);
(*pData1) = psw;
}
}
void Data_SortNWord(uint32_t *SortData, uint32_t len)
{
uint8_t n = 0, m;
for (; n < len - 1; n++)
{
for (m = n + 1; m < len; m++)
{
Data_SwapWord((SortData + n), (SortData + m));
}
}
}
#ifndef _COMMON_INTERFACE_H_
#define _COMMON_INTERFACE_H_
#include "stdint.h"
/*COMMON INTERFACE*/
typedef enum
{
CAN_SIG_NORMAL = 0u,
CAN_SIG_LOST = 0x55U,
} CAN_MSG_Status_t;
typedef enum
{
EX_OK = 0u,
EX_ERR,
} _Fun_Res;
typedef enum
{
COMMON_POWER_OFF = 0x00u,
COMMON_POWER_ON = 0x01u,
COMMON_POWER_UNKNOW = 0xFFu,
} COMMON_PowerStatus_t;
typedef enum
{
COMMON_InValid = 0X00U,
COMMON_Valid = 0X01U,
COMMON_Valid_UNKNOW = 0XFFU,
} DataValid_t;
typedef enum
{
CAN_MSG_TX_CYCLE = 0u,
CAN_MSG_TX_CYCKE_EVENT,
} CAN_TX_Type_t;
typedef enum
{
MSG_STD = 0u,
MSG_EXT,
} CAN_MSG_FORMAT_t;
/*COMMON INTERFACE END*/
typedef enum
{
Bus_Sleep_Mode,
Pre_Bus_Sleep_Mode,
Network_Mode,
} NM_Mode_t;
extern void Common_DataInit(void);
extern void Common_Input_Para(void);
extern uint8_t Common_Get_IG_Sts(void);
extern DataValid_t Common_Get_IG_Sts_Valid(void);
extern void Common_Set_IG_Sts(COMMON_PowerStatus_t Val);
extern void Common_Set_IG_Sts_Valid(DataValid_t Val);
extern uint16_t Common_Get_Act_V_Speed(void);
extern uint16_t Common_Get_Disp_V_Speed(void);
extern DataValid_t Common_Get_Act_V_Speed_Valid(void);
extern DataValid_t Common_Get_Disp_V_Speed_Valid(void);
extern void Common_Set_Act_V_Speed(uint32_t Val);
extern void Common_Set_Disp_V_Speed(uint32_t Val);
extern uint16_t Common_Get_TireSize(void);
extern void Common_Set_Act_V_Speed_Valid(DataValid_t Val);
extern void Common_Set_Disp_V_Speed_Valid(DataValid_t Val);
extern uint16_t Common_Get_DispSpeed(void);
extern uint16_t Get_Self(void);
extern uint32_t Common_GetIgnOnTime(void); /*ms*/
extern uint32_t Common_GetIgnOffTime(void); /*ms*/
extern uint32_t Common_GetIgnOnTimeL(void);
extern uint32_t Data_Km_To_Mile(uint32_t Km);
extern uint32_t Data_Mile_To_Km(uint32_t Mile);
void Data_SwapWord(uint32_t *pData1, uint32_t *pData2);
void Data_SortNWord(uint32_t *SortData, uint32_t len);
#endif
This diff is collapsed.
#ifndef DATA_COOLANT_H
#define DATA_COOLANT_H
#include "Components.h"
typedef struct
{
uint16_t Goal;
uint16_t CoolantTemperatureCurrent;
uint16_t Time;
} CoolantTemperature;
typedef enum{
CoolantSensorNormal = 0u,
CoolantSensorShortCircuit,
CoolantSensorOpenCircuit,
}CoolantSensorSts_t;
extern void Coolant_KL15_Init(void);
extern void Coolant_KL30_Init(void);
extern void Coolant_Cal_Sevice(uint8_t deltaTime);
extern uint8_t Get_CurCoolantSetp(void);
extern CoolantSensorSts_t Get_Coolant_Sensor_State(void);
extern void Coolant_R_Cal(uint8_t deltaTime);
extern uint8_t Get_CurCoolantRed(void);
extern uint16_t Get_Coolant_Percentage(void);
extern void Coolant_Percentage_Figure(uint8_t deltaTime);
extern void Coolant_Self_InspectionOld(void);
#endif
This diff is collapsed.
#ifndef _Data_Espeed_H_
#define _Data_Espeed_H_
#include "common.h"
/******************************************************************************
发动机转速
******************************************************************************/
/*** 参数设置 ***/
#define DATA_ENGINE_RUNNING_THRESHOLD 400 //发动机运转阈值
#define DATA_ENGINE_STOP_THRESHOLD 300 //发动机停止阈值
#define DATA_ESPEED_DAMPING_FACTOR 4 //阻尼系数
#define DATA_ESPEED_INC_STEP 10 //速度增加时慢加速速度变化步长
#define DATA_ESPEED_DEC_STEP 10 //方向改变时急减速速度变化步长
#define DATA_ESPEED_APPR_SPEED_MIN 20 //最小逼近速度
#define DATA_ESPEED_HYSTERESIS 80u //回差
/*** 控制结构 ***/
typedef struct
{
uint16_t Buffer[5];
uint8_t Cnt;
} DataESpeedSamplerStruct; //转速采样结构
typedef struct
{
uint16_t Speed;
uint16_t Delta;
uint8_t Dir;
} DataESPeedDampingStruct; //转速阻尼结构
typedef struct
{
uint16_t ESpeedBackup;
uint16_t Timer;
uint8_t Mode;
} DataESpeedIdleStruct; //怠速处理结构
/******************************************************************************
函数名:Data_Engine_Speed_KL30_Wakeup_Init
功 能:发动机转速初始化函数
参 数:无
返回值:无
******************************************************************************
注 意:该函数KL30初始化/Wakeup初始化被调用一次
******************************************************************************/
void Data_Engine_Speed_KL30_Wakeup_Init (void);
/******************************************************************************
函数名:Data_Engine_Speed_Processing_Service
功 能:发动机转速数据处理函数
参 数:无
返回值:无
******************************************************************************
注 意:该函数必须每20ms被调用一次
******************************************************************************/
void Data_Engine_Speed_Processing_Service ( void );
void Self_Inspection(void);
uint8_t Get_EngineValid(void);
uint16_t Get_ActualEngineSpeed(void);
uint16_t Get_DispEngineSpeed(void);
#endif
This diff is collapsed.
#ifndef DATA_FUEL_H
#define DATA_FUEL_H
// #include "Components.h"
#include "stdint.h"
typedef struct{
uint16_t Fuel_Goal;
uint16_t FuelOilPreCurrent;
uint16_t Time;
} FuelOilSensor;
typedef enum{
FuelSensorNormal = 0,
FuelSensorShortCircuit,
FuelSensorOpenCircuit,
}FuelSensorSts_t;
extern void Fuel_KL15_Init(void);
extern void Fuel_KL30_Init(void);
extern void Fuel_Cal_Sevice(uint8_t deltaTime);
extern uint8_t Get_CurFuelSetp(void);
extern FuelSensorSts_t Get_Fuel_Sensor_State(void);
extern void Fuel_R_Cal(uint8_t deltaTime);
extern uint8_t Get_Fuel_Percentage(void);
extern uint8_t Get_CurFuelRed(void);
// extern void Fuel_Percentage(uint8_t deltaTime);
void Fuel_Self_InspectionOld(void);
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#ifndef _DISPLAY_H_
#define _DISPLAY_H_
#include "common.h"
#include "Components.h"
typedef struct
{
uint8_t Dis_Seconds;
uint8_t Dis_Hour;
uint8_t Dis_Minute;
uint8_t RTC_H12;
uint8_t Dis_Timer_Set;
uint8_t ODO_KM_Memory;
uint8_t Size_Back_Light;
uint32_t Val_ServiceMil100m;
uint32_t Val_ServiceTimer1s;
} DataTimeStruct;
extern void Set_Timer_EE(DataTimeStruct *DataTime);
extern void Display_KL15_KL30_Init(void);
extern void Driving_Mode_Display(void);
extern void Time_Display_Service(void);
extern void Time_Cocln_server(void);
extern void Double_Empvalue(void);
extern void Time_Assignment(void);
extern void TIME_Service(void);
extern void Hour_Adjust(void);
extern void Min_Adjust(void);
// uint8_t D_Flash_Get(void);
// uint8_t D_Flash_Set(void);
extern void ODO_KM_Memory_Feature(void);
extern void Size_Back_Light_Feature(void);
extern uint8_t Get_Dis_Minute_Time(void);
extern uint16_t Get_Driving_Mode(void);
extern uint8_t Get_Dis_Hour_Time(void);
extern uint8_t Get_Time_Cocln(void);
extern uint8_t Get_Flicker(void);
extern uint8_t Get_AMorPM(void);
#endif
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment