403 lines
12 KiB
C
Executable File
403 lines
12 KiB
C
Executable File
/*
|
||
* charger_gbt.c
|
||
*
|
||
* Created on: Apr 18, 2024
|
||
* Author: colorbass
|
||
*/
|
||
|
||
|
||
#include "charger_gbt.h"
|
||
#include "main.h"
|
||
#include "board.h"
|
||
#include "stdio.h"
|
||
#include "j1939.h"
|
||
#include "string.h"
|
||
#include "edcan.h"
|
||
#include "connector.h"
|
||
#include "soft_rtc.h"
|
||
|
||
uint8_t GBT_CC_GetStateRaw();
|
||
|
||
gbtState_t GBT_State;
|
||
uint32_t GBT_state_tick; //Tick after state switch
|
||
uint32_t GBT_delay_start;
|
||
uint32_t GBT_delay;
|
||
/* Флаги приёма пакетов от EVSE (EV получает) */
|
||
uint8_t GBT_CHM_recv; // CHM получен (0x2600) → отвечаем BHM
|
||
uint8_t GBT_CRM_recv; // CRM получен (0x0100) → отвечаем BRM или BCP
|
||
uint8_t GBT_CML_recv; // CML получен (0x0800) → отвечаем BRO
|
||
uint8_t GBT_CST_recv; // CST получен (0x1A00) → EVSE запросил стоп, переходим в STOP
|
||
uint8_t GBT_CSD_recv; // CSD получен (0x1D00) → финальный отчёт EVSE, переходим в STOP_CSD
|
||
|
||
uint8_t GBT_CRO_val; // последнее значение CRO от EVSE (0x0A00)
|
||
|
||
GBT_CML_t GBT_MaxLoad;
|
||
GBT_CRM_t GBT_ChargerInfo;
|
||
|
||
GBT_BHM_t GBT_MaxVoltage;
|
||
GBT_BRM_t GBT_EVInfo;
|
||
GBT_BCP_t GBT_BATStat;
|
||
GBT_BCL_t GBT_ReqPower;
|
||
GBT_BCL_t GBT_CurrPower;
|
||
|
||
GBT_BCS_t GBT_ChargingStatus;
|
||
|
||
GBT_BSM_t GBT_BatteryStatus;
|
||
|
||
GBT_CCS_t GBT_ChargerCurrentStatus;
|
||
|
||
GBT_CSD_t GBT_ChargerStop;
|
||
|
||
uint8_t GBT_BRO;
|
||
|
||
uint32_t GBT_TimeChargingStarted;
|
||
|
||
uint32_t GBT_StopCauseCode;
|
||
uint32_t GBT_ErrorCode;
|
||
|
||
GBT_StopSource_t GBT_StopSource;
|
||
|
||
void GBT_Init(){
|
||
GBT_State = GBT_DISABLED;
|
||
CONN.connControl = CMD_NONE;
|
||
GBT_Reset();
|
||
}
|
||
|
||
|
||
void GBT_ChargerTask(){
|
||
|
||
//GBT_LockTask();
|
||
if(j_rx.state == 2){
|
||
switch (j_rx.PGN){
|
||
case 0x2600: // CHM EVSE->EV (старт/версия GB/T)
|
||
GBT_CHM_recv = 1;
|
||
break;
|
||
|
||
case 0x0100: // CRM EVSE->EV (идентификация зарядника, 0x00 или 0xAA)
|
||
memcpy(&GBT_ChargerInfo, j_rx.data, sizeof(GBT_ChargerInfo));
|
||
GBT_CRM_recv = 1;
|
||
break;
|
||
|
||
case 0x0800: // CML EVSE->EV (макс. параметры зарядника)
|
||
memcpy(&GBT_MaxLoad, j_rx.data, sizeof(GBT_MaxLoad));
|
||
GBT_CML_recv = 1;
|
||
break;
|
||
|
||
case 0x0700: // CTS EVSE->EV (time sync)
|
||
// Пока не используем, но можем сохранить время при необходимости
|
||
break;
|
||
|
||
case 0x0A00: // CRO EVSE->EV (0x00 = инициализация, 0xAA = готов к зарядке)
|
||
GBT_CRO_val = (j_rx.data[0] & 0xFF);
|
||
break;
|
||
|
||
case 0x1200: // CCS EVSE->EV (текущий статус зарядника)
|
||
memcpy(&GBT_ChargerCurrentStatus, j_rx.data, sizeof(GBT_ChargerCurrentStatus));
|
||
CONN.enableLoad = GBT_ChargerCurrentStatus.chargingPermissible;
|
||
CONN.ChargingTime = GBT_ChargerCurrentStatus.chargingTime;
|
||
CONN.MeasuredVoltageSE = GBT_ChargerCurrentStatus.outputVoltage / 10;
|
||
CONN.MeasuredCurrentSE = 4000 - GBT_ChargerCurrentStatus.outputCurrent;
|
||
break;
|
||
|
||
case 0x1A00: // CST EVSE->EV (остановка зарядки по инициативе EVSE)
|
||
GBT_CST_recv = 1;
|
||
break;
|
||
|
||
case 0x1D00: // CSD EVSE->EV (финальный отчёт зарядника)
|
||
memcpy(&GBT_ChargerStop, j_rx.data, sizeof(GBT_ChargerStop));
|
||
GBT_CSD_recv = 1;
|
||
break;
|
||
|
||
case 0x1F00: // CEM EVSE->EV (сообщение об ошибке)
|
||
memcpy(&GBT_ErrorCode, j_rx.data, sizeof(GBT_ErrorCode));
|
||
break;
|
||
}
|
||
j_rx.state = 0;
|
||
}
|
||
|
||
if((HAL_GetTick() - GBT_delay_start) < GBT_delay){
|
||
//waiting
|
||
}else switch (GBT_State){
|
||
case GBT_DISABLED:
|
||
CONN.enableLoad = 0;
|
||
// if(connectorState == Preparing){
|
||
// GBT_Reset();
|
||
// GBT_SwitchState(GBT_EV_CONNECTING);
|
||
// }
|
||
break;
|
||
|
||
/* --- Строгая последовательность GB/T EV: приём от EVSE → ответ EV --- */
|
||
|
||
case GBT_EV_CONNECTING:
|
||
// 1) Ждём CHM (0x2600), ничего не шлём. Получили → переход в GBT_EV_HANDSHAKE
|
||
GBT_Delay(250);
|
||
|
||
if (GBT_CHM_recv) {
|
||
GBT_SwitchState(GBT_EV_HANDSHAKE);
|
||
break;
|
||
}
|
||
if (GBT_StateTick() > 10000) {
|
||
GBT_Error(0xFCF0C0FC);
|
||
EDCAN_printf(LOG_WARN, "CHM timeout\n");
|
||
}
|
||
break;
|
||
|
||
case GBT_EV_HANDSHAKE:
|
||
// 2) Постоянно шлём BHM, ждём CRM (0x0100, первый раз 0x00)
|
||
GBT_MaxVoltage.maxOutputVoltage = 4500; // 450V
|
||
if (j_rx.state == 0) GBT_SendBHM();
|
||
GBT_Delay(250);
|
||
|
||
if (GBT_CRM_recv) {
|
||
GBT_SwitchState(GBT_EV_RECOGNITION);
|
||
break;
|
||
}
|
||
break;
|
||
|
||
|
||
case GBT_EV_RECOGNITION:
|
||
// 3) Постоянно шлём BRM, ждём CRM (0x0100, 0xAA)
|
||
GBT_EVInfo.version[0] = 2;
|
||
GBT_EVInfo.version[1] = 0;
|
||
GBT_EVInfo.version[2] = 0;
|
||
GBT_EVInfo.batteryType = 1;
|
||
GBT_EVInfo.batteryCapacity = 700;
|
||
GBT_EVInfo.batteryVoltage = 3990;
|
||
memcpy(GBT_EVInfo.batteryVendor, "TEST", 4);
|
||
GBT_EVInfo.batterySN = 666666;
|
||
GBT_EVInfo.batteryManuY = 30;
|
||
GBT_EVInfo.batteryManuM = 2;
|
||
GBT_EVInfo.batteryManuD = 20;
|
||
GBT_EVInfo.batteryCycleCount = 666;
|
||
GBT_EVInfo.ownAuto = 1;
|
||
GBT_EVInfo.rsvd0 = 0;
|
||
memcpy(GBT_EVInfo.EVIN, "EDISON_TEST_EVIN_", 17);
|
||
memcpy(GBT_EVInfo.EV_SW_VER, "1.0.0", 8);
|
||
|
||
if (j_rx.state == 0) GBT_SendBRM(); // TODO CHUNKED SEND
|
||
GBT_Delay(250);
|
||
|
||
if ((GBT_CRM_recv) && (GBT_ChargerInfo.bmsIdentified == 0xAA)) {
|
||
GBT_SwitchState(GBT_EV_CHARGING_PARAMETERS);
|
||
break;
|
||
}
|
||
if (GBT_StateTick() > 5000) {
|
||
GBT_Error(0xFCF1C0FC);
|
||
EDCAN_printf(LOG_WARN, "CRM(0xAA) timeout (wait BCP)\n");
|
||
}
|
||
break;
|
||
|
||
case GBT_EV_CHARGING_PARAMETERS:
|
||
// 4) Постоянно шлём BCP, ждём CML (0x0800) → шлём BRO(0xAA)
|
||
if (j_rx.state == 0) GBT_SendBCP();
|
||
GBT_Delay(250);
|
||
|
||
if (GBT_CML_recv) {
|
||
GBT_SwitchState(GBT_EV_BMS_INIT);
|
||
break;
|
||
}
|
||
if (GBT_StateTick() > 5000) {
|
||
GBT_Error(0xFCF4C0FC);
|
||
EDCAN_printf(LOG_WARN, "CML timeout\n");
|
||
}
|
||
break;
|
||
case GBT_EV_BMS_INIT:
|
||
// 5) Постоянно шлём BRO(0x00) и ждем инициализацию CRO(0xAA)
|
||
if (j_rx.state == 0) GBT_SendBRO(0x00);
|
||
GBT_Delay(250);
|
||
if (GBT_StateTick() > 1500) {
|
||
GBT_SwitchState(GBT_EV_WAIT_CHARGER_READY);
|
||
break;
|
||
}
|
||
|
||
break;
|
||
|
||
case GBT_EV_WAIT_CHARGER_READY:
|
||
// 5) Постоянно шлём BRO(0xAA) и ждем инициализацию CRO(0xAA)
|
||
if (j_rx.state == 0) GBT_SendBRO(0xAA);
|
||
|
||
GBT_Delay(250);
|
||
|
||
if (GBT_CRO_val == 0xAA) {
|
||
GBT_SwitchState(GBT_EV_CHARGING);
|
||
GBT_TimeChargingStarted = get_Current_Time();
|
||
break;
|
||
}
|
||
|
||
break;
|
||
|
||
case GBT_EV_CHARGING:
|
||
// Основной режим зарядки: EV периодически шлёт BCS/BSM.
|
||
GBT_ReqPower.requestedVoltage = CONN.RequestedVoltage * 10;
|
||
GBT_ReqPower.requestedCurrent = 4000 - CONN.RequestedCurrent;
|
||
GBT_ReqPower.chargingMode = 1;
|
||
|
||
GBT_BATStat.maxCellVoltage = 320;
|
||
GBT_BATStat.maxChargingCurrent = 40;
|
||
GBT_BATStat.totalEnergy = 6;
|
||
GBT_BATStat.maxChargingVoltage = 500;
|
||
GBT_BATStat.maxTemp = 70;
|
||
GBT_BATStat.SOC = CONN.SOC;
|
||
GBT_BATStat.measVoltage = CONN.MeasuredVoltage;
|
||
|
||
// Стоп по инициативе EVSE (получили CST)
|
||
if (GBT_CST_recv) {
|
||
GBT_StopEVSE(GBT_CST_SUDDENSTOP);
|
||
break;
|
||
}
|
||
// Стоп по команде с машины (EDCAN)
|
||
if (CONN.connControl == CMD_STOP) {
|
||
GBT_StopEV(GBT_CST_BMS_ACTIVELY_SUSPENDS);
|
||
break;
|
||
}
|
||
if (IN_ReadInput(IN_ESTOP)) {
|
||
GBT_StopEV(GBT_CST_BMS_ACTIVELY_SUSPENDS);
|
||
break;
|
||
}
|
||
|
||
GBT_SendBCS();
|
||
GBT_SendBCL();
|
||
GBT_SendBSM();
|
||
GBT_Delay(250);
|
||
break;
|
||
|
||
case GBT_STOP:
|
||
GBT_Delay(10);
|
||
CONN.enableLoad = 0;
|
||
// EV шлёт BSD (Battery Stop Data), не CST (CST шлёт EVSE)
|
||
GBT_SendBSD();
|
||
if (GBT_StateTick() > 10000) {
|
||
EDCAN_printf(LOG_WARN, "CSD Timeout\n");
|
||
GBT_Error(0xFCF0C0FD); // CSD timeout
|
||
}
|
||
if (GBT_CSD_recv) {
|
||
GBT_SwitchState(GBT_STOP_CSD);
|
||
}
|
||
break;
|
||
|
||
case GBT_STOP_CSD:
|
||
// EV не шлёт CSD (финальный отчёт шлёт EVSE). Ждём 2.5 с и завершаем.
|
||
GBT_Delay(250);
|
||
if (GBT_StateTick() > 2500) {
|
||
GBT_SwitchState(GBT_COMPLETE);
|
||
}
|
||
break;
|
||
|
||
|
||
case GBT_ERROR:
|
||
//GBT_SendBEM(GBT_ErrorCode); //2.5S TODO
|
||
GBT_SwitchState(GBT_COMPLETE);
|
||
// GBT_Reset();
|
||
//
|
||
break;
|
||
|
||
case GBT_COMPLETE:
|
||
if(connectorState != Finished) {
|
||
GBT_SwitchState(GBT_DISABLED);
|
||
GBT_Reset();//CHECK
|
||
}
|
||
break;
|
||
|
||
default:
|
||
GBT_SwitchState(GBT_DISABLED);
|
||
}
|
||
if (CONN_CC_GetState()==GBT_CC_4V) CONN.EvseConnected = 1;
|
||
else CONN.EvseConnected = 0;
|
||
}
|
||
|
||
|
||
|
||
void GBT_SwitchState(gbtState_t state){
|
||
GBT_State = state;
|
||
GBT_state_tick = HAL_GetTick();
|
||
|
||
if(GBT_State == GBT_DISABLED) EDCAN_printf(LOG_INFO, "GBT_DISABLED\n");
|
||
if(GBT_State == GBT_EV_CONNECTING) EDCAN_printf(LOG_INFO, "GBT_EV_CONNECTING\n");
|
||
if(GBT_State == GBT_EV_HANDSHAKE) EDCAN_printf(LOG_INFO, "GBT_EV_HANDSHAKE\n");
|
||
if(GBT_State == GBT_EV_RECOGNITION) EDCAN_printf(LOG_INFO, "GBT_EV_RECOGNITION\n");
|
||
if(GBT_State == GBT_EV_CHARGING_PARAMETERS) EDCAN_printf(LOG_INFO, "GBT_EV_CHARGING_PARAMETERS\n");
|
||
if(GBT_State == GBT_EV_BMS_INIT) EDCAN_printf(LOG_INFO, "GBT_EV_BMS_INIT\n");
|
||
if(GBT_State == GBT_EV_WAIT_CHARGER_READY) EDCAN_printf(LOG_INFO, "GBT_EV_WAIT_CHARGER_READY\n");
|
||
if(GBT_State == GBT_EV_CHARGING) EDCAN_printf(LOG_INFO, "GBT_EV_CHARGING\n");
|
||
if(GBT_State == GBT_STOP) EDCAN_printf(LOG_INFO, "GBT_STOP\n");
|
||
if(GBT_State == GBT_STOP_CSD) EDCAN_printf(LOG_INFO, "GBT_STOP_CSD\n");
|
||
if(GBT_State == GBT_ERROR) EDCAN_printf(LOG_WARN, "GBT_ERROR\n");
|
||
if(GBT_State == GBT_COMPLETE) EDCAN_printf(LOG_INFO, "GBT_COMPLETE\n");
|
||
|
||
|
||
}
|
||
|
||
uint32_t GBT_StateTick(){
|
||
return HAL_GetTick() - GBT_state_tick;
|
||
}
|
||
|
||
void GBT_Delay(uint32_t delay){
|
||
GBT_delay_start = HAL_GetTick();
|
||
GBT_delay = delay;
|
||
}
|
||
|
||
void GBT_StopEV(uint32_t causecode){ // --> Suspend EV
|
||
if (CONN.chargingError){
|
||
GBT_StopSource = GBT_STOP_EVSE;
|
||
}else{
|
||
GBT_StopSource = GBT_STOP_EV;
|
||
}
|
||
GBT_StopCauseCode = causecode;
|
||
if(GBT_State != GBT_STOP) GBT_SwitchState(GBT_STOP);
|
||
}
|
||
|
||
void GBT_StopEVSE(uint32_t causecode){ // --> Suspend EVSE
|
||
GBT_StopSource = GBT_STOP_EVSE;
|
||
GBT_StopCauseCode = causecode;
|
||
if(GBT_State != GBT_STOP) GBT_SwitchState(GBT_STOP);
|
||
}
|
||
|
||
void GBT_StopOCPP(uint32_t causecode){ // --> Finished
|
||
GBT_StopSource = GBT_STOP_OCPP;
|
||
GBT_StopCauseCode = causecode;
|
||
if(GBT_State != GBT_STOP) GBT_SwitchState(GBT_STOP);
|
||
}
|
||
|
||
void GBT_ForceStop(){ // --> Suspend EV
|
||
GBT_StopSource = GBT_STOP_EV;
|
||
// Отключаем силовой контактор батареи со стороны EV
|
||
CONN.enableLoad = 0;
|
||
GBT_SwitchState(GBT_COMPLETE);
|
||
}
|
||
|
||
void GBT_Error(uint32_t errorcode){ // --> Suspend EV
|
||
GBT_StopSource = GBT_STOP_EV;
|
||
EDCAN_printf(LOG_WARN, "GBT Error code: 0x%X\n", errorcode);
|
||
GBT_ErrorCode = errorcode;
|
||
GBT_SwitchState(GBT_ERROR);
|
||
}
|
||
|
||
|
||
void GBT_Reset(){
|
||
GBT_SwitchState(GBT_DISABLED);
|
||
GBT_CHM_recv = 0;
|
||
GBT_CRM_recv = 0;
|
||
GBT_CML_recv = 0;
|
||
GBT_CST_recv = 0;
|
||
GBT_CSD_recv = 0;
|
||
GBT_CRO_val = 0x00;
|
||
CONN.SOC = 0;
|
||
CONN.enableLoad = 0;
|
||
CONN.RequestedCurrent = 1000;
|
||
CONN.RequestedVoltage = 400;
|
||
CONN.chargingError = 0;
|
||
memset(&GBT_EVInfo, 0, sizeof (GBT_EVInfo));
|
||
memset(&GBT_BATStat, 0, sizeof (GBT_BATStat));
|
||
memset(&GBT_ReqPower, 0, sizeof (GBT_ReqPower));
|
||
memset(&GBT_CurrPower, 0, sizeof (GBT_CurrPower));
|
||
memset(&GBT_MaxVoltage, 0, sizeof (GBT_MaxVoltage));
|
||
memset(&GBT_ChargingStatus, 0, sizeof (GBT_ChargingStatus));
|
||
memset(&GBT_BatteryStatus, 0, sizeof (GBT_BatteryStatus));
|
||
memset(&GBT_ChargerCurrentStatus, 0, sizeof (GBT_ChargerCurrentStatus));
|
||
memset(&GBT_ChargerStop, 0, sizeof (GBT_ChargerStop));
|
||
GBT_CurrPower.requestedCurrent = 4000; //0A
|
||
GBT_CurrPower.requestedVoltage = 500; //50V
|
||
GBT_TimeChargingStarted = 0;
|
||
GBT_BRO = 0x00;
|
||
}
|