Files
CCSModuleSW30Web/Core/Src/charger_gbt.c

578 lines
16 KiB
C
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 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 "lock.h"
#include "connector.h"
#include "soft_rtc.h"
#include "debug.h"
#include "charger_config.h"
#include "serial_control.h"
#include "lock.h"
#include "psu_control.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;
uint8_t GBT_BAT_INFO_recv;
uint8_t GBT_BAT_STAT_recv;
uint8_t GBT_BRO_recv;
uint8_t GBT_BHM_recv;
uint8_t GBT_BSD_recv;
uint8_t EV_ready;
//uint8_t GBT_Charger_Enable; //FIX
//uint8_t GBT_Charger_Permission;//FIX
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;
/** Время последнего приёма любого из PGN BCL/BCS/BSM; общий таймаут в GBT_S10_CHARGING */
uint32_t GBT_last_BCL_BCS_BSM_tick;
#define GBT_BCL_BCS_BSM_TIMEOUT_MS 2000
uint32_t GBT_StopCauseCode;
uint32_t GBT_ErrorCode;
GBT_StopSource_t GBT_StopSource;
extern ConfigBlock_t config;
void GBT_Init(){
GBT_State = GBT_DISABLED;
GBT_Reset();
GBT_MaxLoad.maxOutputVoltage = PSU_MAX_VOLTAGE*10; // 1000V
GBT_MaxLoad.minOutputVoltage = PSU_MIN_VOLTAGE*10; //150V
GBT_MaxLoad.maxOutputCurrent = 4000 - (PSU_MAX_CURRENT*10); //100A
GBT_MaxLoad.minOutputCurrent = 4000 - (PSU_MIN_CURRENT*10); //1A
}
void GBT_SetConfig(){
set_Time(config.unixTime);
GBT_ChargerInfo.chargerLocation[0] = config.location[0];
GBT_ChargerInfo.chargerLocation[1] = config.location[1];
GBT_ChargerInfo.chargerLocation[2] = config.location[2];
GBT_ChargerInfo.chargerNumber = config.chargerNumber;
}
void GBT_ChargerTask(){
//GBT_LockTask();
if(j_rx.state == 2){
switch (j_rx.PGN){
case 0x2700: //PGN BHM
GBT_BHM_recv = 1;
memcpy (&GBT_MaxVoltage, j_rx.data, sizeof(GBT_MaxVoltage));
break;
case 0x0200: //PGN BRM LONG
GBT_BAT_INFO_recv = 1;
memcpy (&GBT_EVInfo, j_rx.data, sizeof(GBT_EVInfo));
break;
case 0x0600: //PGN BCP LONG
GBT_BAT_STAT_recv = 1;
memcpy (&GBT_BATStat, j_rx.data, sizeof(GBT_BATStat));
break;
case 0x0900: //PGN BRO
GBT_BRO_recv = 1;
if(j_rx.data[0] == 0xAA) EV_ready = 1;
else EV_ready = 0;
GBT_BRO = j_rx.data[0];
break;
case 0x1000: //PGN BCL
GBT_last_BCL_BCS_BSM_tick = HAL_GetTick();
//TODO: power block
memcpy (&GBT_ReqPower, j_rx.data, sizeof(GBT_ReqPower));
uint16_t volt = GBT_ReqPower.requestedVoltage; // 0.1V/bit
uint16_t curr = 4000 - GBT_ReqPower.requestedCurrent; // 0.1A/bit
CONN.RequestedVoltage = volt / 10; // В
CONN.WantedCurrent = curr; // 0.1A
break;
case 0x1100: //PGN BCS
GBT_last_BCL_BCS_BSM_tick = HAL_GetTick();
//TODO
memcpy (&GBT_ChargingStatus, j_rx.data, sizeof(GBT_ChargingStatus));
CONN.SOC = GBT_ChargingStatus.currentChargeState;
break;
case 0x1300: //PGN BSM
GBT_last_BCL_BCS_BSM_tick = HAL_GetTick();
//TODO
memcpy (&GBT_BatteryStatus, j_rx.data, sizeof(GBT_BatteryStatus));
break;
case 0x1500: //PGN BMV
//TODO
break;
case 0x1600: //PGN BMT
//TODO
break;
case 0x1700: //PGN BSP
//TODO
break;
//this handler in j1939.c
// case 0x1900: //PGN BST
// break;
case 0x1C00: //PGN BSD
//TODO SOC Voltage Temp
GBT_BSD_recv = 1;
break;
//this handler in j1939.c
// case 0x1E00: //PGN BEM
// break;
//BSM BMV BMT BSP BST BSD BEM
}
j_rx.state = 0;
}
if((HAL_GetTick() - GBT_delay_start) < GBT_delay){
//waiting
}else switch (GBT_State){
case GBT_DISABLED:
RELAY_Write(RELAY_AUX0, 0);
RELAY_Write(RELAY_AUX1, 0);
if(connectorState == Preparing){
GBT_Reset();
GBT_Start();//TODO IF protections (maybe not needed)
}
break;
case GBT_S3_STARTED:
GBT_SwitchState(GBT_S31_WAIT_BHM);
GBT_Delay(500);
break;
case GBT_S31_WAIT_BHM:
if(j_rx.state == 0) GBT_SendCHM();
GBT_Delay(250);
if(GBT_BHM_recv) {
GBT_SwitchState(GBT_S4_WAIT_PSU_READY);
}
//Timeout 10S
if((GBT_BHM_recv == 0) && (GBT_StateTick()>10000)) { //BHM Timeout
GBT_Error(0xFCF0C0FC);
CONN.chargingError = CONN_ERR_EV_COMM;
log_printf(LOG_ERR, "BHM Timeout\n");
}
break;
case GBT_S4_WAIT_PSU_READY:
if(j_rx.state == 0) GBT_SendCHM();
GBT_Delay(250);
if(PSU0.ready){
GBT_SwitchState(GBT_S4_WAIT_PSU_ON);
}
if(GBT_StateTick()>10000){
GBT_StopEVSE(GBT_CST_OTHERFALUT);
CONN.chargingError = CONN_ERR_PSU_FAULT;
log_printf(LOG_ERR, "PSU ready timeout, stopping...\n");
break;
}
break;
case GBT_S4_WAIT_PSU_ON:
if(j_rx.state == 0) GBT_SendCHM();
GBT_Delay(250);
CONN.RequestedVoltage = GBT_MaxVoltage.maxOutputVoltage / 10; // 0.1V -> V
CONN.WantedCurrent = 10; // 1A max (0.1A units)
CONN.EnableOutput = 1;
if(PSU0.state == PSU_CONNECTED){
GBT_SwitchState(GBT_S4_ISOTEST);
}
if(GBT_StateTick()>10000){
GBT_StopEVSE(GBT_CST_OTHERFALUT);
CONN.chargingError = CONN_ERR_PSU_FAULT;
log_printf(LOG_ERR, "PSU on timeout, stopping...\n");
break;
}
break;
case GBT_S4_ISOTEST:
if(j_rx.state == 0) GBT_SendCHM();
GBT_Delay(250);
//TODO: Isolation test trigger
if(CONN.chargingError != CONN_NO_ERROR){
GBT_StopEVSE(GBT_CST_OTHERFALUT);
}
if(GBT_StateTick()>5000){
GBT_SwitchState(GBT_S4_WAIT_PSU_OFF);
}
break;
case GBT_S4_WAIT_PSU_OFF:
CONN.RequestedVoltage = 0;
CONN.WantedCurrent = 0;
CONN.EnableOutput = 0;
if(GBT_StateTick()>5000){
GBT_StopEVSE(GBT_CST_OTHERFALUT);
CONN.chargingError = CONN_ERR_PSU_FAULT;
log_printf(LOG_ERR, "PSU off timeout, stopping...\n");
break;
}
if(PSU0.PSU_enabled == 0){
GBT_SwitchState(GBT_S5_BAT_INFO);
}
break;
case GBT_S5_BAT_INFO:
if(j_rx.state == 0) GBT_SendCRM(0x00);
GBT_Delay(250);
if(GBT_BAT_INFO_recv){ //BRM
//Got battery info
GBT_SwitchState(GBT_S6_BAT_STAT);
log_printf(LOG_INFO, "EV info:\n");
log_printf(LOG_INFO, "GBT_ver V%d.%d%d\n",GBT_EVInfo.version[0],GBT_EVInfo.version[1],GBT_EVInfo.version[2]);
log_printf(LOG_INFO, "Battery type: %d\n",GBT_EVInfo.batteryType);
log_printf(LOG_INFO, "Battery capacity: %d\n", GBT_EVInfo.batteryCapacity); // 0.1Ah/bit
log_printf(LOG_INFO, "Battery voltage: %d\n", GBT_EVInfo.batteryVoltage); // 0.1V/bit
log_printf(LOG_INFO, "Battery vendor: %.4s\n", GBT_EVInfo.batteryVendor); // Battery vendor (ASCII string)
log_printf(LOG_INFO, "Battery SN: %lu\n", GBT_EVInfo.batterySN); // int
log_printf(LOG_INFO, "Battery manufacture date: %02d.%02d.%04d\n", GBT_EVInfo.batteryManuD, GBT_EVInfo.batteryManuM ,GBT_EVInfo.batteryManuY+1985); // year (offset 1985)
log_printf(LOG_INFO, "Battery cycles: %d\n", GBT_EVInfo.batteryCycleCount); //uint24_t
log_printf(LOG_INFO, "Own auto: %d\n", GBT_EVInfo.ownAuto); // 0 = lizing, 1 = own auto
log_printf(LOG_INFO, "EVIN: %.17s\n", GBT_EVInfo.EVIN); //EVIN
log_printf(LOG_INFO, "EV_SW_VER: %.8s\n", GBT_EVInfo.EV_SW_VER);
}
//Timeout
if((GBT_StateTick()>5000) && (GBT_BAT_INFO_recv == 0)){
CONN.chargingError = CONN_ERR_EV_COMM;
GBT_Error(0xFDF0C0FC); //BRM Timeout
log_printf(LOG_ERR, "BRM Timeout\n");
}
break;
case GBT_S6_BAT_STAT:
if(j_rx.state == 0) GBT_SendCRM(0xAA);
GBT_Delay(250);
if(GBT_BAT_STAT_recv){
//Got battery status
GBT_SwitchState(GBT_S7_BMS_WAIT);
log_printf(LOG_INFO, "Battery info:\n");
log_printf(LOG_INFO, "maxCV %dV\n",GBT_BATStat.maxCellVoltage/100); // 0.01v/bit
log_printf(LOG_INFO, "maxCC %dA\n",GBT_BATStat.maxChargingCurrent/10); // 0.1A/bit
log_printf(LOG_INFO, "totE %dkWh\n",GBT_BATStat.totalEnergy/10); // 0.1kWh
log_printf(LOG_INFO, "maxCV %dV\n",GBT_BATStat.maxChargingVoltage/10); // 0.1V/ bit
log_printf(LOG_INFO, "maxT %dC\n",(int16_t)GBT_BATStat.maxTemp-50); // 1C/bit, -50C offset
log_printf(LOG_INFO, "SOC %dp\n",GBT_BATStat.SOC/10); // 0.1%/bit , 0..100%
log_printf(LOG_INFO, "Volt. %dV\n",GBT_BATStat.measVoltage/10); // 0.1V/bit
}
if((GBT_StateTick()>5000) && (GBT_BAT_STAT_recv == 0)){
CONN.chargingError = CONN_ERR_EV_COMM;
GBT_Error(0xFCF1C0FC); //BCP Timeout
log_printf(LOG_ERR, "BCP Timeout\n");
}
break;
case GBT_S7_BMS_WAIT:
if(j_rx.state == 0) GBT_SendCTS();
HAL_Delay(2);
if(j_rx.state == 0) GBT_SendCML();
GBT_Delay(250);
if((GBT_StateTick()>5000) && (GBT_BRO_recv == 0)){
CONN.chargingError = CONN_ERR_EV_COMM;
GBT_Error(0xFCF4C0FC); //BRO Timeout
log_printf(LOG_ERR, "BRO Timeout\n");
}
if(EV_ready){
//EV ready (AA)
GBT_SwitchState(GBT_S8_INIT_CHARGER);
}else{
if((GBT_StateTick()>60000) && (GBT_BRO_recv == 1)){
CONN.chargingError = CONN_ERR_EV_COMM;
GBT_Error(0xFCF4C0FC); //BRO Timeout
log_printf(LOG_ERR, "EV not ready for a 60s\n");
}
}
break;
case GBT_S8_INIT_CHARGER:
if(j_rx.state == 0) GBT_SendCRO(0x00);
//TODO
GBT_Delay(250);
// if(GBT_StateTick()>1500){
if(PSU0.ready){
//Power Modules initiated
GBT_SwitchState(GBT_S9_WAIT_BCL);
}
if((GBT_StateTick()>6000) && (PSU0.ready == 0)){
GBT_StopEVSE(GBT_CST_OTHERFALUT);
CONN.chargingError = CONN_ERR_PSU_FAULT;
log_printf(LOG_ERR, "PSU not ready, stopping...\n");
}
break;
case GBT_S9_WAIT_BCL:
if(j_rx.state == 0) GBT_SendCRO(0xAA);
GBT_Delay(250);
if(GBT_ReqPower.chargingMode != 0){ //REFACTORING
//BCL power requirements received
GBT_SwitchState(GBT_S10_CHARGING);
GBT_last_BCL_BCS_BSM_tick = HAL_GetTick();
CONN_SetState(Charging);
uint16_t curr = 4000 - GBT_ReqPower.requestedCurrent;
uint16_t volt = GBT_ReqPower.requestedVoltage;
//TODO Limits
CONN.RequestedVoltage = volt / 10; // В
CONN.WantedCurrent = curr; // 0.1A
CONN.EnableOutput = 1;
GBT_TimeChargingStarted = get_Current_Time();
}
break;
case GBT_S10_CHARGING:
//CHARGING
if((HAL_GetTick() - GBT_last_BCL_BCS_BSM_tick) > GBT_BCL_BCS_BSM_TIMEOUT_MS){
GBT_StopEVSE(GBT_CST_OTHERFALUT);
CONN.chargingError = CONN_ERR_EV_COMM;
log_printf(LOG_WARN, "BCL/BCS/BSM timeout, stopping...\n");
break;
}
if(CONN.connControl == CMD_STOP) GBT_StopOCPP(GBT_CST_SUSPENDS_ARTIFICIALLY);
if(CONN.connControl == CMD_FORCE_UNLOCK) GBT_StopOCPP(GBT_CST_SUSPENDS_ARTIFICIALLY); // --> Finished
if(GBT_LockState.error) {
GBT_StopEVSE(GBT_CST_OTHERFALUT); // --> Suspend EVSE
CONN.chargingError = CONN_ERR_LOCK;
log_printf(LOG_WARN, "Lock error, stopping...\n");
break;
}
if(CONN_CC_GetState()!=GBT_CC_4V){
GBT_StopEVSE(GBT_CST_OTHERFALUT);
CONN.chargingError = CONN_ERR_HOTPLUG;
log_printf(LOG_WARN, "Hotplug detected, stopping...\n");
break;
}
if((GBT_ReadTemp(0) > 90) || (GBT_ReadTemp(1) > 90)) {
GBT_StopEVSE(GBT_CST_CONNECTOR_OVER_TEMP);
CONN.chargingError = CONN_ERR_CONN_TEMP;
log_printf(LOG_WARN, "Connector overheat %d %d, stopping...\n", GBT_ReadTemp(0), GBT_ReadTemp(1));
break;
}
if(CONN.chargingError != CONN_NO_ERROR){ // --> Suspend EVSE
GBT_StopEVSE(GBT_CST_OTHERFALUT);
// log_printf(LOG_WARN, "Isolation error\n");
}
//GBT_ChargerCurrentStatus.chargingPermissible = 0b1111111111111100;//NOT PERMITTED
GBT_ChargerCurrentStatus.chargingPermissible = 0b1111111111111101;
GBT_ChargerCurrentStatus.chargingTime = (get_Current_Time() - GBT_TimeChargingStarted)/60;
GBT_ChargerCurrentStatus.outputCurrent = 4000 - CONN.MeasuredCurrent; // 0.1A
GBT_ChargerCurrentStatus.outputVoltage = CONN.MeasuredVoltage * 10; // V -> 0.1V
if(j_rx.state == 0) {
GBT_SendCCS();
GBT_Delay(49);
}else{
GBT_Delay(10); // Resend packet if not sent
}
//TODO: снижение тока если перегрев контактов
break;
case GBT_STOP:
GBT_Delay(10);
CONN.EnableOutput = 0;
GBT_SendCST(GBT_StopCauseCode);
//RELAY_Write(RELAY_OUTPUT, 0);
//GBT_SwitchState(GBT_DISABLED);
if(GBT_StateTick()>10000){
log_printf(LOG_ERR, "BSD Timeout\n");
GBT_Error(0xFCF0C0FD); //BSD Timeout
}
if(GBT_BSD_recv != 0){
GBT_SwitchState(GBT_STOP_CSD);
}
break;
case GBT_STOP_CSD:
GBT_Delay(250);
GBT_SendCSD();
if(GBT_StateTick()>2500){ //2.5S
GBT_SwitchState(GBT_COMPLETE);
}
break;
case GBT_ERROR:
GBT_SendCEM(GBT_ErrorCode); //2.5S
GBT_SwitchState(GBT_COMPLETE);
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.EvConnected = 1;
else CONN.EvConnected = 0;
}
void GBT_SwitchState(gbtState_t state){
GBT_State = state;
GBT_state_tick = HAL_GetTick();
if(GBT_State == GBT_DISABLED) log_printf(LOG_INFO, "Disabled\n");
if(GBT_State == GBT_S3_STARTED) log_printf(LOG_INFO, "Charging started\n");
if(GBT_State == GBT_S31_WAIT_BHM) log_printf(LOG_INFO, "Waiting for BHM\n");
if(GBT_State == GBT_S4_WAIT_PSU_READY) log_printf(LOG_INFO, "Waiting for PSU ready\n");
if(GBT_State == GBT_S4_ISOTEST) log_printf(LOG_INFO, "Isolation test\n");
if(GBT_State == GBT_S5_BAT_INFO) log_printf(LOG_INFO, "Waiting for battery info\n");
if(GBT_State == GBT_S6_BAT_STAT) log_printf(LOG_INFO, "Waiting for battery status\n");
if(GBT_State == GBT_S7_BMS_WAIT) log_printf(LOG_INFO, "Waiting for BMS\n");
if(GBT_State == GBT_S8_INIT_CHARGER)log_printf(LOG_INFO, "Initializing charger\n");
if(GBT_State == GBT_S9_WAIT_BCL) log_printf(LOG_INFO, "Waiting for BCL\n");
if(GBT_State == GBT_S10_CHARGING) log_printf(LOG_INFO, "Charging in progress\n");
if(GBT_State == GBT_STOP) log_printf(LOG_INFO, "Charging Stopped\n");
if(GBT_State == GBT_STOP_CSD) log_printf(LOG_INFO, "Charging Stopped with CSD\n");
if(GBT_State == GBT_ERROR) log_printf(LOG_INFO, "Charging Error\n");
if(GBT_State == GBT_COMPLETE) log_printf(LOG_INFO, "Charging Finished\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;
CONN.EnableOutput = 0;
GBT_SwitchState(GBT_COMPLETE);
GBT_Lock(0);
RELAY_Write(RELAY_AUX0, 0);
RELAY_Write(RELAY_AUX1, 0);
}
void GBT_Error(uint32_t errorcode){ // --> Suspend EV
GBT_StopSource = GBT_STOP_EV;
log_printf(LOG_ERR, "GBT Error code: 0x%X\n", errorcode);
GBT_ErrorCode = errorcode;
GBT_SwitchState(GBT_ERROR);
}
void GBT_Reset(){
GBT_last_BCL_BCS_BSM_tick = HAL_GetTick();
GBT_BAT_INFO_recv = 0;
GBT_BAT_STAT_recv = 0;
GBT_BRO_recv = 0;
GBT_BHM_recv = 0;
GBT_BSD_recv = 0;
EV_ready = 0;
CONN.SOC = 0;
CONN.EnableOutput = 0;
CONN.WantedCurrent = 0;
CONN.RequestedVoltage = 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;
GBT_LockResetError();
}
void GBT_Start(){
RELAY_Write(RELAY_AUX0, 1);
RELAY_Write(RELAY_AUX1, 1);
GBT_SwitchState(GBT_S3_STARTED);
}