/* * 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); } if(ISO.isolationResistance < (ISO.voltageComm/2)){ // *100/1000 CONN.chargingError = CONN_ERR_INSULATION; log_printf(LOG_WARN, "Isolation warning\n"); } // 500 Ohm/V if(ISO.isolationResistance < (ISO.voltageComm/10)){ // *100/1000 CONN.chargingError = CONN_ERR_INSULATION; log_printf(LOG_WARN, "Current leakage, insulation error, stopping...\n"); GBT_StopEVSE(GBT_CST_OTHERFALUT); } // 100 Ohm/V 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(ISO.isolationResistance < (ISO.voltageComm/10)){ // *100/1000 CONN.chargingError = CONN_ERR_INSULATION; log_printf(LOG_WARN, "Current leakage, insulation error, stopping...\n"); } // 100 Ohm/V if(CONN.chargingError != CONN_NO_ERROR){ // --> Suspend EVSE GBT_StopEVSE(GBT_CST_OTHERFALUT); } //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); }