diff --git a/.cproject b/.cproject
new file mode 100755
index 0000000..2e87624
--- /dev/null
+++ b/.cproject
@@ -0,0 +1,188 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index a81a02d..c36dcd0 100755
--- a/.gitignore
+++ b/.gitignore
@@ -1,138 +1,55 @@
-# ---> C
-# Prerequisites
-*.d
+# =========================
+# STM32CubeIDE / STM32 GCC
+# =========================
-# Object files
+# Build output folders
+/Debug/
+/Release/
+
+# Generated compiler/linker artifacts
*.o
-*.ko
*.obj
-*.elf
-
-# Linker output
-*.ilk
-*.map
-*.exp
-
-# Precompiled Headers
-*.gch
-*.pch
-
-# Libraries
-*.lib
-*.a
-*.la
-*.lo
-
-# Shared objects (inc. Windows DLLs)
-*.dll
-*.so
-*.so.*
-*.dylib
-
-# Executables
-*.exe
-*.out
-*.app
-*.i*86
-*.x86_64
-*.hex
-
-# Debug files
-*.dSYM/
+*.d
*.su
-*.idb
-*.pdb
-
-# Kernel Module Compile Results
-*.mod*
-*.cmd
-.tmp_versions/
-modules.order
-Module.symvers
-Mkfile.old
-dkms.conf
-
-# ---> CMake
-CMakeLists.txt.user
-CMakeCache.txt
-CMakeFiles
-CMakeScripts
-Testing
-Makefile
-cmake_install.cmake
-install_manifest.txt
-compile_commands.json
-CTestTestfile.cmake
-_deps
-
-# ---> Eclipse
-.metadata
-bin/
-tmp/
-*.tmp
-*.bak
-*.swp
-*~.nib
-local.properties
-.settings/
-.loadpath
-.recommenders
-
-# External tool builders
-.externalToolBuilders/
-
-# Locally stored "Eclipse launch configurations"
-*.launch
-
-# PyDev specific (Python IDE for Eclipse)
-*.pydevproject
-
-# CDT-specific (C/C++ Development Tooling)
-.cproject
-
-# CDT- autotools
-.autotools
-
-# Java annotation processor (APT)
-.factorypath
-
-# PDT-specific (PHP Development Tools)
-.buildpath
-
-# sbteclipse plugin
-.target
-
-# Tern plugin
-.tern-project
-
-# TeXlipse plugin
-.texlipse
-
-# STS (Spring Tool Suite)
-.springBeans
-
-# Code Recommenders
-.recommenders/
-
-# Annotation Processing
-.apt_generated/
-.apt_generated_test/
-
-# Scala IDE specific (Scala & Java development for Eclipse)
-.cache-main
-.scala_dependencies
-.worksheet
-
-# Uncomment this line if you wish to ignore the project description file.
-# Typically, this file would be tracked if it contains build/dependency configurations:
-#.project
-
-# ---> macOS
-.DS_Store
-
-# ---> STM32CubeIDE / ARM GCC
-*.bin
*.cyclo
*.list
+*.map
+*.a
+*.lib
+*.out
+*.exp
+*.ilk
+subdir.mk
+sources.mk
+objects.mk
+
+# Firmware and executable deliverables (keep out of source history)
+*.elf
+*.axf
+*.bin
+*.hex
*.srec
*.verilog
+
+# Captured logs/traces
+/logs/
+*.log
+
+# Local IDE/OS temp files
+.DS_Store
+*.swp
+*.tmp
+*.bak
+*~
+.metadata/
+.externalToolBuilders/
+
+# Local launch configurations
+*.launch
+
+# Keep project descriptors/versioned configuration
+!.project
+!.cproject
+!.settings/
+!.mxproject
+!*.ioc
diff --git a/.settings/com.st.stm32cube.ide.mcu.sfrview.prefs b/.settings/com.st.stm32cube.ide.mcu.sfrview.prefs
new file mode 100755
index 0000000..98a69fc
--- /dev/null
+++ b/.settings/com.st.stm32cube.ide.mcu.sfrview.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+sfrviewstate={"fFavorites"\:{"fLists"\:{}},"fProperties"\:{"fNodeProperties"\:{}}}
diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml
new file mode 100755
index 0000000..dae24b6
--- /dev/null
+++ b/.settings/language.settings.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.settings/org.eclipse.cdt.core.prefs b/.settings/org.eclipse.cdt.core.prefs
new file mode 100755
index 0000000..c8ec5df
--- /dev/null
+++ b/.settings/org.eclipse.cdt.core.prefs
@@ -0,0 +1,6 @@
+doxygen/doxygen_new_line_after_brief=true
+doxygen/doxygen_use_brief_tag=false
+doxygen/doxygen_use_javadoc_tags=true
+doxygen/doxygen_use_pre_tag=false
+doxygen/doxygen_use_structural_commands=false
+eclipse.preferences.version=1
diff --git a/.settings/stm32cubeide.project.prefs b/.settings/stm32cubeide.project.prefs
new file mode 100755
index 0000000..e3e642d
--- /dev/null
+++ b/.settings/stm32cubeide.project.prefs
@@ -0,0 +1,5 @@
+2F62501ED4689FB349E356AB974DBE57=0A9B2D4C5DCB32842F05F53136A1D1D7
+66BE74F758C12D739921AEA421D593D3=1
+8DF89ED150041C4CBC7CB9A9CAA90856=0A9B2D4C5DCB32842F05F53136A1D1D7
+DC22A860405A8BF2F2C095E5B6529F12=283F84148D7B38E239E7ECD52C68B71F
+eclipse.preferences.version=1
diff --git a/Core/Inc/board.h b/Core/Inc/board.h
index 5618121..b45c548 100755
--- a/Core/Inc/board.h
+++ b/Core/Inc/board.h
@@ -17,7 +17,7 @@ typedef enum{
RELAY_3,
RELAY_4,
RELAY_5,
-
+ RELAY_CP,
}relay_t;
typedef enum{
diff --git a/Core/Inc/charger_gbt.h b/Core/Inc/charger_gbt.h
index 0889995..97881b6 100755
--- a/Core/Inc/charger_gbt.h
+++ b/Core/Inc/charger_gbt.h
@@ -222,6 +222,7 @@ extern GBT_BSM_t GBT_BatteryStatus;
extern GBT_CSD_t GBT_ChargerStop;
extern uint8_t GBT_BRO;
+extern uint8_t cc_enable;
extern uint8_t GBT_Charger_Enable;
@@ -254,6 +255,7 @@ void GBT_SendBRO(uint8_t state);
void GBT_SendBCL(void);
void GBT_SendBCS(void);
void GBT_SendBSM(void);
+void GBT_SendBST(uint32_t causeCode);
void GBT_SendBSD(void);
diff --git a/Core/Inc/connector.h b/Core/Inc/connector.h
index 5ff26b1..9665825 100755
--- a/Core/Inc/connector.h
+++ b/Core/Inc/connector.h
@@ -75,13 +75,35 @@ typedef struct {
uint8_t connectorType; // 0 - NONE, 1 - GBT, 2 - CCS (для EV всегда GBT)
} CONN_t;
-extern CONN_t CONN;
+extern CONN_t CONN[2];
void CONN_Init();
void CONN_Task();
void CONN_SetState(CONN_State_t state);
+void CONN_CC_ReadStateFiltered(void);
uint8_t CONN_CC_GetStateRaw();
uint8_t CONN_CC_GetState();
float CONN_CC_GetAdc();
+// STM32(EV) -> EVerest (EVSE)
+// uint8_t SOC; // State of charge [%] // 2
+// uint16_t RequestedVoltage; // 1V/bit
+// uint16_t RequestedCurrent; // 0.1A/bit
+// uint16_t MeasuredVoltage; // 1V/bit
+// uint16_t MeasuredCurrent; // 0.1A/bit
+// uint8_t ContactorEnabled; // 1 - enabled, 0 - disabled (команда на замыкание контактора)
+
+// cp_state
+// stop ????
+
+
+// EVerest (EVSE) -> STM32(EV)
+// uint16_t MeasuredVoltageSE; // 1V/bit
+// uint16_t MeasuredCurrentSE; // 0.1A/bit
+// uint8_t enableLoad; // 1 - enabled, 0 - disabled (команда на включение контактора)
+
+// cp_state
+// pwm_value
+
+
#endif /* INC_CONNECTOR_H_ */
diff --git a/Core/Inc/cp.h b/Core/Inc/cp.h
new file mode 100644
index 0000000..f98bb29
--- /dev/null
+++ b/Core/Inc/cp.h
@@ -0,0 +1,28 @@
+#ifndef INC_CP_H_
+#define INC_CP_H_
+
+#include "main.h"
+
+typedef enum {
+ EV_STATE_A_IDLE = 0,
+ EV_STATE_B_CONN_PREP = 1,
+ EV_STATE_C_CONN_ACTIVE = 2,
+ EV_STATE_D_CONN_ACT_VENT = 3,
+ EV_STATE_E_NO_POWER = 4,
+ EV_STATE_F_ERROR = 5,
+ EV_STATE_ACQUIRING = 6,
+} CP_State_t;
+
+typedef struct {
+ uint32_t frequency_hz;
+ uint8_t duty_percent;
+ uint8_t valid;
+} CP_Measurement_t;
+
+extern volatile CP_State_t cp_state;
+
+void CP_Init(void);
+void CP_Task(void);
+CP_Measurement_t CP_GetMeasurement(void);
+
+#endif /* INC_CP_H_ */
diff --git a/Core/Inc/debug.h b/Core/Inc/debug.h
index 1543b68..48bef46 100755
--- a/Core/Inc/debug.h
+++ b/Core/Inc/debug.h
@@ -8,9 +8,13 @@
#ifndef SRC_DEBUG_H_
#define SRC_DEBUG_H_
-void debug_task();
-void debug_init();
-void debug_rx_interrupt(UART_HandleTypeDef *huart, uint16_t Size);
+#include
+#include "edcan.h"
+
+void debug_buffer_add(const uint8_t* data, uint16_t len);
+uint16_t debug_buffer_available(void);
+void debug_buffer_send(void);
+int log_printf(int level, const char *format, ...);
#endif /* SRC_DEBUG_H_ */
diff --git a/Core/Inc/j1939.h b/Core/Inc/j1939.h
index 4c6dce5..139c4e8 100755
--- a/Core/Inc/j1939.h
+++ b/Core/Inc/j1939.h
@@ -27,11 +27,31 @@ typedef struct{
uint32_t tick;
}j_receive_t;
+typedef struct{
+ uint32_t ExtId;
+ uint8_t DLC;
+ uint8_t data[8];
+ uint32_t tick;
+}j1939_rx_frame_t;
+
+typedef struct{
+ uint32_t ExtId;
+ uint8_t DLC;
+ uint8_t data[8];
+}j1939_tx_frame_t;
+
extern j_receive_t j_rx;
void J_SendCTS(j_receive_t rx);
void J_SendACK(j_receive_t rx);
+void J1939_ExchangeRxBuffer(void);
+void J1939_ExchangeTxBuffer(void);
+void J1939_InitBuffers(void);
+uint16_t J1939_GetRxBufferCount(void);
+uint16_t J1939_GetTxBufferCount(void);
+uint32_t J1939_GetRxOverflowCount(void);
+uint32_t J1939_GetTxOverflowCount(void);
void GBT_CAN_ReInit();
diff --git a/Core/Inc/load.h b/Core/Inc/load.h
new file mode 100644
index 0000000..e1f0ec9
--- /dev/null
+++ b/Core/Inc/load.h
@@ -0,0 +1,6 @@
+#pragma once
+
+#include "main.h"
+
+void LOAD_Init();
+void LOAD_Task();
\ No newline at end of file
diff --git a/Core/Inc/main.h b/Core/Inc/main.h
index b4d87da..2cd6224 100644
--- a/Core/Inc/main.h
+++ b/Core/Inc/main.h
@@ -57,12 +57,20 @@ void Error_Handler(void);
/* USER CODE END EFP */
/* Private defines -----------------------------------------------------------*/
+#define CP_STATE_F_Pin GPIO_PIN_2
+#define CP_STATE_F_GPIO_Port GPIOC
+#define CP_RELAY_Pin GPIO_PIN_3
+#define CP_RELAY_GPIO_Port GPIOC
#define IN_SW0_Pin GPIO_PIN_1
#define IN_SW0_GPIO_Port GPIOA
#define IN_SW1_Pin GPIO_PIN_2
#define IN_SW1_GPIO_Port GPIOA
+#define CP_STATE_C_Pin GPIO_PIN_5
+#define CP_STATE_C_GPIO_Port GPIOA
#define ADC_CC1_Pin GPIO_PIN_6
#define ADC_CC1_GPIO_Port GPIOA
+#define CP_PWM_Pin GPIO_PIN_7
+#define CP_PWM_GPIO_Port GPIOA
#define LOCK_A_Pin GPIO_PIN_4
#define LOCK_A_GPIO_Port GPIOC
#define LOCK_B_Pin GPIO_PIN_5
@@ -73,16 +81,16 @@ void Error_Handler(void);
#define ADC_NTC2_GPIO_Port GPIOB
#define IN0_Pin GPIO_PIN_7
#define IN0_GPIO_Port GPIOE
-#define RELAY5_Pin GPIO_PIN_8
-#define RELAY5_GPIO_Port GPIOE
-#define RELAY4_Pin GPIO_PIN_9
-#define RELAY4_GPIO_Port GPIOE
+#define RELAY1_Pin GPIO_PIN_8
+#define RELAY1_GPIO_Port GPIOE
+#define RELAY2_Pin GPIO_PIN_9
+#define RELAY2_GPIO_Port GPIOE
#define RELAY3_Pin GPIO_PIN_10
#define RELAY3_GPIO_Port GPIOE
-#define RELAY2_Pin GPIO_PIN_11
-#define RELAY2_GPIO_Port GPIOE
-#define RELAY1_Pin GPIO_PIN_12
-#define RELAY1_GPIO_Port GPIOE
+#define RELAY4_Pin GPIO_PIN_11
+#define RELAY4_GPIO_Port GPIOE
+#define RELAY5_Pin GPIO_PIN_12
+#define RELAY5_GPIO_Port GPIOE
#define AC_OK_Pin GPIO_PIN_14
#define AC_OK_GPIO_Port GPIOE
#define RELAY_CC_Pin GPIO_PIN_15
diff --git a/Core/Inc/serial_control.h b/Core/Inc/serial_control.h
new file mode 100644
index 0000000..ee703ce
--- /dev/null
+++ b/Core/Inc/serial_control.h
@@ -0,0 +1,130 @@
+#ifndef SERIAL_CONTROL_H
+#define SERIAL_CONTROL_H
+
+#include
+#include "main.h"
+#include "connector.h"
+
+/* Read-only commands */
+#define CMD_GET_INFO 0x01
+#define CMD_ISOLATION_STATUS 0x01 /* UART5 isolation block packet */
+#define CMD_GET_GBT_STATUS 0x02
+#define CMD_GET_CCS_STATUS 0x03
+#define CMD_GET_LOG 0x50
+#define CMD_GET_LOG_CONTINUE 0x51
+
+/* GBT control commands */
+#define CMD_GBT_CC_ENABLE 0x10
+#define CMD_GBT_STOP 0x11
+#define CMD_GBT_SET_SOC 0x12
+#define CMD_GBT_SET_REQUEST 0x13
+#define CMD_GBT_SET_VIN 0x18
+
+/* CCS control commands */
+#define CMD_CCS_SET_STATE 0x20
+#define CMD_CCS_ENABLE_LOAD 0x24
+
+/* Response codes */
+#define RESP_SUCCESS 0x12
+#define RESP_FAILED 0x13
+#define RESP_INVALID 0x14
+
+#define MAX_TX_BUFFER_SIZE 256
+#define MAX_RX_BUFFER_SIZE 256
+#define CRC32_POLYNOMIAL ((uint32_t)0xEDB88320)
+
+typedef struct __attribute__((packed)) {
+ uint8_t command;
+ uint8_t argument_length;
+ void *argument;
+} ReceivedCommand_t;
+
+typedef enum {
+ SC_SOURCE_UART2 = 0,
+ SC_SOURCE_UART5 = 1,
+} SC_Source_t;
+
+typedef struct __attribute__((packed)) {
+ uint8_t isolationStatus;
+ uint16_t isolationResistance;
+ int16_t voltageHigh;
+ int16_t voltageLow;
+ int16_t voltageComm;
+} IsolationStatusPacket_t;
+
+typedef struct __attribute__((packed)) {
+ uint16_t requestedVoltage; /* 1V/bit */
+ uint16_t requestedCurrent; /* 0.1A/bit */
+} EvSetLimits_t;
+
+typedef struct __attribute__((packed)) {
+ uint16_t measuredVoltage; /* 1V/bit */
+ uint16_t measuredCurrent; /* 0.1A/bit */
+} EvSetMeasured_t;
+
+typedef struct __attribute__((packed)) {
+ uint8_t connector_type; /* 0x01 (GBT) */
+ uint16_t requestedVoltage; /* V */
+ uint16_t requestedCurrent; /* 0.1A/bit */
+ uint16_t measuredVoltageSE; /* V */
+ uint16_t measuredCurrentSE; /* 0.1A/bit */
+ uint16_t measuredVoltage; /* 1V/bit */
+ uint16_t measuredCurrent; /* 0.1A/bit */
+ uint8_t cc_enabled;
+ uint8_t contactorEnabled;
+ CONN_Error_t chargingError;
+ uint8_t EvseConnected;
+ uint8_t soc; /* % */
+ uint8_t vin[17];
+ uint8_t cc_state;
+ uint8_t logs_available;
+ CONN_State_t connState;
+} GBT_MonitorPacket_t;
+
+typedef struct __attribute__((packed)) {
+ uint8_t connector_type; /* 0x02 (CCS) */
+ uint16_t measuredVoltage; /* 1V/bit */
+ uint16_t measuredCurrent; /* 0.1A/bit */
+ uint8_t cp_enabled;
+ uint8_t contactorEnabled;
+ CONN_Error_t chargingError;
+ uint8_t EvseConnected;
+ uint8_t soc; /* % */
+ uint8_t cp_state; /* A/B/C/D/E/... enum value */
+ uint8_t cp_pwm_duty; /* % */
+ CONN_State_t connState;
+} CCS_MonitorPacket_t;
+
+typedef struct __attribute__((packed)) {
+ uint16_t serialNumber;
+ uint8_t boardVersion;
+ uint8_t stationType;
+ uint16_t fw_version_major;
+ uint16_t fw_version_minor;
+ uint16_t fw_version_patch;
+} InfoPacket_t;
+
+typedef struct SerialControl_t SerialControl_t;
+struct SerialControl_t {
+ uint8_t tx_buffer[MAX_TX_BUFFER_SIZE];
+ uint8_t rx_buffer[MAX_RX_BUFFER_SIZE];
+ volatile ReceivedCommand_t received_command;
+ volatile uint8_t command_ready;
+ volatile uint8_t response_pending;
+ volatile uint8_t response_code;
+ volatile uint32_t tx_tick;
+};
+
+void SC_Init(void);
+void SC_Task(void);
+void SC_SendPacket(const uint8_t *payload, uint16_t payload_len, uint8_t response_code);
+void SC_CommandHandler(ReceivedCommand_t *cmd);
+
+extern SerialControl_t serial_control;
+extern GBT_MonitorPacket_t gbtMonitorPacket;
+extern CCS_MonitorPacket_t ccsMonitorPacket;
+extern InfoPacket_t infoPacket;
+extern IsolationStatusPacket_t ISO;
+extern volatile SC_Source_t g_sc_command_source;
+
+#endif /* SERIAL_CONTROL_H */
diff --git a/Core/Inc/stm32f1xx_it.h b/Core/Inc/stm32f1xx_it.h
index 5de19e6..2528f6e 100644
--- a/Core/Inc/stm32f1xx_it.h
+++ b/Core/Inc/stm32f1xx_it.h
@@ -56,7 +56,9 @@ void DebugMon_Handler(void);
void PendSV_Handler(void);
void SysTick_Handler(void);
void CAN1_RX0_IRQHandler(void);
+void TIM3_IRQHandler(void);
void USART2_IRQHandler(void);
+void UART5_IRQHandler(void);
void CAN2_TX_IRQHandler(void);
void CAN2_RX1_IRQHandler(void);
/* USER CODE BEGIN EFP */
diff --git a/Core/Inc/tim.h b/Core/Inc/tim.h
index 3894a40..39b0151 100644
--- a/Core/Inc/tim.h
+++ b/Core/Inc/tim.h
@@ -32,12 +32,15 @@ extern "C" {
/* USER CODE END Includes */
+extern TIM_HandleTypeDef htim3;
+
extern TIM_HandleTypeDef htim4;
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
+void MX_TIM3_Init(void);
void MX_TIM4_Init(void);
void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim);
diff --git a/Core/Src/adc.c b/Core/Src/adc.c
index ed54e8f..50cdc96 100644
--- a/Core/Src/adc.c
+++ b/Core/Src/adc.c
@@ -85,11 +85,12 @@ void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
__HAL_RCC_GPIOB_CLK_ENABLE();
/**ADC1 GPIO Configuration
PA3 ------> ADC1_IN3
+ PA4 ------> ADC1_IN4
PA6 ------> ADC1_IN6
PB0 ------> ADC1_IN8
PB1 ------> ADC1_IN9
*/
- GPIO_InitStruct.Pin = GPIO_PIN_3|ADC_CC1_Pin;
+ GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_4|ADC_CC1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
@@ -116,11 +117,12 @@ void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
/**ADC1 GPIO Configuration
PA3 ------> ADC1_IN3
+ PA4 ------> ADC1_IN4
PA6 ------> ADC1_IN6
PB0 ------> ADC1_IN8
PB1 ------> ADC1_IN9
*/
- HAL_GPIO_DeInit(GPIOA, GPIO_PIN_3|ADC_CC1_Pin);
+ HAL_GPIO_DeInit(GPIOA, GPIO_PIN_3|GPIO_PIN_4|ADC_CC1_Pin);
HAL_GPIO_DeInit(GPIOB, ADC_NTC1_Pin|ADC_NTC2_Pin);
diff --git a/Core/Src/board.c b/Core/Src/board.c
index 40e7944..572b705 100755
--- a/Core/Src/board.c
+++ b/Core/Src/board.c
@@ -20,6 +20,7 @@ void RELAY_Write(relay_t num, uint8_t state){
if(num==RELAY_4)HAL_GPIO_WritePin(RELAY4_GPIO_Port, RELAY4_Pin, state);
if(num==RELAY_5)HAL_GPIO_WritePin(RELAY5_GPIO_Port, RELAY5_Pin, state);
if(num==RELAY_CC)HAL_GPIO_WritePin(RELAY_CC_GPIO_Port, RELAY_CC_Pin, state);
+ if(num==RELAY_CP)HAL_GPIO_WritePin(CP_RELAY_GPIO_Port, CP_RELAY_Pin, state);
}
@@ -74,7 +75,8 @@ void Init_Peripheral(){
RELAY_Write(RELAY_3, 0);
RELAY_Write(RELAY_4, 0);
RELAY_Write(RELAY_5, 0);
- RELAY_Write(RELAY_CC, 1);
+ RELAY_Write(RELAY_CC, 0);
+ RELAY_Write(RELAY_CP, 0);
}
diff --git a/Core/Src/charger_gbt.c b/Core/Src/charger_gbt.c
index 3e3e31b..457be06 100755
--- a/Core/Src/charger_gbt.c
+++ b/Core/Src/charger_gbt.c
@@ -15,6 +15,7 @@
#include "edcan.h"
#include "connector.h"
#include "soft_rtc.h"
+#include "debug.h"
uint8_t GBT_CC_GetStateRaw();
@@ -49,6 +50,7 @@ GBT_CCS_t GBT_ChargerCurrentStatus;
GBT_CSD_t GBT_ChargerStop;
uint8_t GBT_BRO;
+uint8_t cc_enable;
uint32_t GBT_TimeChargingStarted;
@@ -57,17 +59,28 @@ uint32_t GBT_ErrorCode;
GBT_StopSource_t GBT_StopSource;
+static uint32_t GBT_EVSE_last_rx_tick;
+
+#define GBT_EV_HANDSHAKE_TIMEOUT_MS 10000U
+#define GBT_EV_WAIT_READY_TIMEOUT_MS 10000U
+#define GBT_EV_CHARGING_RX_TIMEOUT_MS 3000U
+
void GBT_Init(){
GBT_State = GBT_DISABLED;
- CONN.connControl = CMD_NONE;
+ CONN[0].connControl = CMD_NONE;
+ cc_enable = 0U;
+ memcpy(GBT_EVInfo.EVIN, "EDISON_TEST_EVIN_", 17);
+ memcpy(GBT_EVInfo.EV_SW_VER, "1.0.0", 8);
GBT_Reset();
}
void GBT_ChargerTask(){
+ RELAY_Write(RELAY_CC, cc_enable);
//GBT_LockTask();
if(j_rx.state == 2){
+ GBT_EVSE_last_rx_tick = HAL_GetTick();
switch (j_rx.PGN){
case 0x2600: // CHM EVSE->EV (старт/версия GB/T)
GBT_CHM_recv = 1;
@@ -93,10 +106,12 @@ void GBT_ChargerTask(){
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;
+ if(GBT_State == GBT_EV_CHARGING) {
+ CONN[0].enableLoad = GBT_ChargerCurrentStatus.chargingPermissible;
+ }
+ CONN[0].ChargingTime = GBT_ChargerCurrentStatus.chargingTime;
+ CONN[0].MeasuredVoltageSE = GBT_ChargerCurrentStatus.outputVoltage / 10;
+ CONN[0].MeasuredCurrentSE = 4000 - GBT_ChargerCurrentStatus.outputCurrent;
break;
case 0x1A00: // CST EVSE->EV (остановка зарядки по инициативе EVSE)
@@ -115,11 +130,18 @@ void GBT_ChargerTask(){
j_rx.state = 0;
}
+ if((connectorState == Unplugged) && (GBT_State != GBT_DISABLED)){
+ log_printf(LOG_INFO, "Car unplugged, resetting charge session\n");
+ CONN[0].enableLoad = 0;
+ GBT_Reset();
+ return;
+ }
+
if((HAL_GetTick() - GBT_delay_start) < GBT_delay){
//waiting
}else switch (GBT_State){
case GBT_DISABLED:
- CONN.enableLoad = 0;
+ CONN[0].enableLoad = 0;
// if(connectorState == Preparing){
// GBT_Reset();
// GBT_SwitchState(GBT_EV_CONNECTING);
@@ -133,25 +155,31 @@ void GBT_ChargerTask(){
GBT_Delay(250);
if (GBT_CHM_recv) {
+ log_printf(LOG_INFO, "CHM received, starting EV handshake\n");
GBT_SwitchState(GBT_EV_HANDSHAKE);
break;
}
if (GBT_StateTick() > 10000) {
GBT_Error(0xFCF0C0FC);
- EDCAN_printf(LOG_WARN, "CHM timeout\n");
+ log_printf(LOG_WARN, "CHM timeout\n");
}
break;
case GBT_EV_HANDSHAKE:
// 2) Постоянно шлём BHM, ждём CRM (0x0100, первый раз 0x00)
- GBT_MaxVoltage.maxOutputVoltage = 4500; // 450V
+ GBT_MaxVoltage.maxOutputVoltage = CONN[0].RequestedVoltage * 10;
if (j_rx.state == 0) GBT_SendBHM();
GBT_Delay(250);
if (GBT_CRM_recv) {
+ log_printf(LOG_INFO, "CRM received, sending BRM (EV identification)\n");
GBT_SwitchState(GBT_EV_RECOGNITION);
break;
}
+ if (GBT_StateTick() > GBT_EV_HANDSHAKE_TIMEOUT_MS) {
+ GBT_Error(0xFCF0C0FD);
+ log_printf(LOG_WARN, "CRM timeout in EV_HANDSHAKE\n");
+ }
break;
@@ -171,19 +199,18 @@ void GBT_ChargerTask(){
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)) {
+ log_printf(LOG_INFO, "EV identified by charger, sending BCP\n");
GBT_SwitchState(GBT_EV_CHARGING_PARAMETERS);
break;
}
if (GBT_StateTick() > 5000) {
GBT_Error(0xFCF1C0FC);
- EDCAN_printf(LOG_WARN, "CRM(0xAA) timeout (wait BCP)\n");
+ log_printf(LOG_WARN, "CRM(0xAA) timeout (wait BCP)\n");
}
break;
@@ -193,12 +220,13 @@ void GBT_ChargerTask(){
GBT_Delay(250);
if (GBT_CML_recv) {
+ log_printf(LOG_INFO, "CML received, starting BMS initialization\n");
GBT_SwitchState(GBT_EV_BMS_INIT);
break;
}
if (GBT_StateTick() > 5000) {
GBT_Error(0xFCF4C0FC);
- EDCAN_printf(LOG_WARN, "CML timeout\n");
+ log_printf(LOG_WARN, "CML timeout\n");
}
break;
case GBT_EV_BMS_INIT:
@@ -206,6 +234,7 @@ void GBT_ChargerTask(){
if (j_rx.state == 0) GBT_SendBRO(0x00);
GBT_Delay(250);
if (GBT_StateTick() > 1500) {
+ log_printf(LOG_INFO, "BMS initialized, waiting charger ready signal\n");
GBT_SwitchState(GBT_EV_WAIT_CHARGER_READY);
break;
}
@@ -219,17 +248,23 @@ void GBT_ChargerTask(){
GBT_Delay(250);
if (GBT_CRO_val == 0xAA) {
+ log_printf(LOG_INFO, "Charger ready, entering active charging\n");
GBT_SwitchState(GBT_EV_CHARGING);
GBT_TimeChargingStarted = get_Current_Time();
+ GBT_EVSE_last_rx_tick = HAL_GetTick();
break;
}
+ if (GBT_StateTick() > GBT_EV_WAIT_READY_TIMEOUT_MS) {
+ GBT_Error(0xFCF2C0FD);
+ log_printf(LOG_WARN, "CRO(0xAA) timeout in EV_WAIT_CHARGER_READY\n");
+ }
break;
case GBT_EV_CHARGING:
// Основной режим зарядки: EV периодически шлёт BCS/BSM.
- GBT_ReqPower.requestedVoltage = CONN.RequestedVoltage * 10;
- GBT_ReqPower.requestedCurrent = 4000 - CONN.RequestedCurrent;
+ GBT_ReqPower.requestedVoltage = CONN[0].RequestedVoltage * 10;
+ GBT_ReqPower.requestedCurrent = 4000 - CONN[0].RequestedCurrent;
GBT_ReqPower.chargingMode = 1;
GBT_BATStat.maxCellVoltage = 320;
@@ -237,23 +272,32 @@ void GBT_ChargerTask(){
GBT_BATStat.totalEnergy = 6;
GBT_BATStat.maxChargingVoltage = 500;
GBT_BATStat.maxTemp = 70;
- GBT_BATStat.SOC = CONN.SOC;
- GBT_BATStat.measVoltage = CONN.MeasuredVoltage;
+ GBT_BATStat.SOC = CONN[0].SOC;
+ GBT_BATStat.measVoltage = CONN[0].MeasuredVoltage;
// Стоп по инициативе EVSE (получили CST)
if (GBT_CST_recv) {
+ log_printf(LOG_INFO, "Charging stop requested by EVSE (CST)\n");
GBT_StopEVSE(GBT_CST_SUDDENSTOP);
break;
}
// Стоп по команде с машины (EDCAN)
- if (CONN.connControl == CMD_STOP) {
+ if (CONN[0].connControl == CMD_STOP) {
+ CONN[0].connControl = CMD_NONE;
+ log_printf(LOG_INFO, "Charging stop requested by EV command\n");
GBT_StopEV(GBT_CST_BMS_ACTIVELY_SUSPENDS);
break;
}
if (IN_ReadInput(IN_ESTOP)) {
+ log_printf(LOG_INFO, "Charging stop requested by emergency input\n");
GBT_StopEV(GBT_CST_BMS_ACTIVELY_SUSPENDS);
break;
}
+ if ((HAL_GetTick() - GBT_EVSE_last_rx_tick) > GBT_EV_CHARGING_RX_TIMEOUT_MS) {
+ log_printf(LOG_WARN, "EVSE RX timeout in EV_CHARGING\n");
+ GBT_StopEVSE(GBT_CST_SUDDENSTOP);
+ break;
+ }
GBT_SendBCS();
GBT_SendBCL();
@@ -263,14 +307,23 @@ void GBT_ChargerTask(){
case GBT_STOP:
GBT_Delay(10);
- CONN.enableLoad = 0;
- // EV шлёт BSD (Battery Stop Data), не CST (CST шлёт EVSE)
- GBT_SendBSD();
+ CONN[0].enableLoad = 0;
+ if (GBT_StopSource == GBT_STOP_EV) {
+ // EV-инициированный stop: сначала BST, ждём ответный CST, потом BSD.
+ GBT_SendBST(GBT_StopCauseCode);
+ if (GBT_CST_recv) {
+ GBT_SendBSD();
+ }
+ } else {
+ // EVSE-инициированный stop: EV сразу отвечает BSD.
+ GBT_SendBSD();
+ }
if (GBT_StateTick() > 10000) {
- EDCAN_printf(LOG_WARN, "CSD Timeout\n");
+ log_printf(LOG_WARN, "CSD Timeout\n");
GBT_Error(0xFCF0C0FD); // CSD timeout
}
if (GBT_CSD_recv) {
+ log_printf(LOG_INFO, "CSD received, finalizing charge session\n");
GBT_SwitchState(GBT_STOP_CSD);
}
break;
@@ -279,6 +332,7 @@ void GBT_ChargerTask(){
// EV не шлёт CSD (финальный отчёт шлёт EVSE). Ждём 2.5 с и завершаем.
GBT_Delay(250);
if (GBT_StateTick() > 2500) {
+ log_printf(LOG_INFO, "Charge session completed\n");
GBT_SwitchState(GBT_COMPLETE);
}
break;
@@ -301,8 +355,8 @@ void GBT_ChargerTask(){
default:
GBT_SwitchState(GBT_DISABLED);
}
- if (CONN_CC_GetState()==GBT_CC_4V) CONN.EvseConnected = 1;
- else CONN.EvseConnected = 0;
+ if (CONN_CC_GetState()==GBT_CC_4V) CONN[0].EvseConnected = 1;
+ else CONN[0].EvseConnected = 0;
}
@@ -311,18 +365,18 @@ 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");
+ if(GBT_State == GBT_DISABLED) log_printf(LOG_DEBUG, "DBG_STATE: GBT_DISABLED\n");
+ if(GBT_State == GBT_EV_CONNECTING) log_printf(LOG_DEBUG, "DBG_STATE: GBT_EV_CONNECTING\n");
+ if(GBT_State == GBT_EV_HANDSHAKE) log_printf(LOG_DEBUG, "DBG_STATE: GBT_EV_HANDSHAKE\n");
+ if(GBT_State == GBT_EV_RECOGNITION) log_printf(LOG_DEBUG, "DBG_STATE: GBT_EV_RECOGNITION\n");
+ if(GBT_State == GBT_EV_CHARGING_PARAMETERS) log_printf(LOG_DEBUG, "DBG_STATE: GBT_EV_CHARGING_PARAMETERS\n");
+ if(GBT_State == GBT_EV_BMS_INIT) log_printf(LOG_DEBUG, "DBG_STATE: GBT_EV_BMS_INIT\n");
+ if(GBT_State == GBT_EV_WAIT_CHARGER_READY) log_printf(LOG_DEBUG, "DBG_STATE: GBT_EV_WAIT_CHARGER_READY\n");
+ if(GBT_State == GBT_EV_CHARGING) log_printf(LOG_DEBUG, "DBG_STATE: GBT_EV_CHARGING\n");
+ if(GBT_State == GBT_STOP) log_printf(LOG_DEBUG, "DBG_STATE: GBT_STOP\n");
+ if(GBT_State == GBT_STOP_CSD) log_printf(LOG_DEBUG, "DBG_STATE: GBT_STOP_CSD\n");
+ if(GBT_State == GBT_COMPLETE) log_printf(LOG_DEBUG, "DBG_STATE: GBT_COMPLETE\n");
+ if(GBT_State == GBT_ERROR) log_printf(LOG_WARN, "State machine entered ERROR state\n");
}
@@ -337,7 +391,7 @@ void GBT_Delay(uint32_t delay){
}
void GBT_StopEV(uint32_t causecode){ // --> Suspend EV
- if (CONN.chargingError){
+ if (CONN[0].chargingError){
GBT_StopSource = GBT_STOP_EVSE;
}else{
GBT_StopSource = GBT_STOP_EV;
@@ -361,13 +415,13 @@ void GBT_StopOCPP(uint32_t causecode){ // --> Finished
void GBT_ForceStop(){ // --> Suspend EV
GBT_StopSource = GBT_STOP_EV;
// Отключаем силовой контактор батареи со стороны EV
- CONN.enableLoad = 0;
+ CONN[0].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);
+ log_printf(LOG_WARN, "GBT Error code: 0x%X\n", errorcode);
GBT_ErrorCode = errorcode;
GBT_SwitchState(GBT_ERROR);
}
@@ -381,11 +435,11 @@ void GBT_Reset(){
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;
+ CONN[0].SOC = 0;
+ CONN[0].enableLoad = 0;
+ CONN[0].RequestedCurrent = 1000;
+ CONN[0].RequestedVoltage = 400;
+ CONN[0].chargingError = 0;
memset(&GBT_EVInfo, 0, sizeof (GBT_EVInfo));
memset(&GBT_BATStat, 0, sizeof (GBT_BATStat));
memset(&GBT_ReqPower, 0, sizeof (GBT_ReqPower));
@@ -399,4 +453,5 @@ void GBT_Reset(){
GBT_CurrPower.requestedVoltage = 500; //50V
GBT_TimeChargingStarted = 0;
GBT_BRO = 0x00;
+ GBT_EVSE_last_rx_tick = HAL_GetTick();
}
diff --git a/Core/Src/connector.c b/Core/Src/connector.c
index 6b43655..2093225 100755
--- a/Core/Src/connector.c
+++ b/Core/Src/connector.c
@@ -7,12 +7,14 @@
#include "connector.h"
#include "board.h"
#include "edcan.h"
+#include "debug.h"
#include
#include
CONN_State_t connectorState;
-CONN_t CONN;
+// CONN[0] - GB/T, CONN[1] - CCS (reserved for future use)
+CONN_t CONN[2];
uint8_t CC_STATE_FILTERED;
@@ -20,19 +22,18 @@ static void CONN_UpdateEdcanOutput(void);
void CONN_Init(){
memset(&CONN, 0, sizeof(CONN));
- CONN.connControl = CMD_NONE;
+ CONN[0].connControl = CMD_NONE;
CONN_SetState(Unknown);
}
void CONN_Task(){
-
switch (connectorState){
case Unknown:
CONN_SetState(Unplugged);
break;
case Disabled:
- if(CONN.chargingError == 0) {
+ if(CONN[0].chargingError == 0) {
CONN_SetState(Unplugged);
}
break;
@@ -40,10 +41,11 @@ void CONN_Task(){
{
// Обновляем признак физического подключения разъёма по уровню CC
if(CONN_CC_GetState() == GBT_CC_4V){
- CONN.EvseConnected = 1;
+ CONN[0].EvseConnected = 1;
+ log_printf(LOG_INFO, "Charger plugged, waiting for 12V AUX\n");
CONN_SetState(AuthRequired);
}else{
- CONN.EvseConnected = 0;
+ CONN[0].EvseConnected = 0;
}
break;
}
@@ -52,6 +54,7 @@ void CONN_Task(){
{
// Если уровень CC вернулся к 6/12В – считаем, что коннектор выдернули
if(CONN_CC_GetState() != GBT_CC_4V){
+ log_printf(LOG_INFO, "Charger unplugged\n");
CONN_SetState(Unplugged);
GBT_Reset();
break;
@@ -59,6 +62,7 @@ void CONN_Task(){
// Как только появляется 12V AUX от станции – переходим в Preparing (инициализация протокола)
if(IN_ReadInput(IN_0) == 1){
+ log_printf(LOG_INFO, "12V AUX detected, starting session\n");
CONN_SetState(Preparing);
GBT_SwitchState(GBT_EV_CONNECTING);
}
@@ -69,11 +73,15 @@ void CONN_Task(){
// Ожидаем переход стейт-машины GB/T в режим зарядки.
// Как только GBT_State уходит в режим CHARGING – считаем, что начался заряд.
if(GBT_State == GBT_EV_CHARGING){
+ log_printf(LOG_INFO, "Charging started\n");
CONN_SetState(Charging);
}
- if(IN_ReadInput(IN_0) == 0){
- CONN_SetState(Unplugged);
- GBT_Reset();
+// if(IN_ReadInput(IN_0) == 0){
+// CONN_SetState(Unplugged);
+// GBT_Reset();
+// }
+ if(GBT_State == GBT_DISABLED){
+ CONN_SetState(Finished);
}
break;
@@ -84,6 +92,7 @@ void CONN_Task(){
CONN_SetState(Finished);
}
if(IN_ReadInput(IN_0) == 0){
+ log_printf(LOG_INFO, "12V AUX removed, finishing session\n");
CONN_SetState(Finished);
}
break;
@@ -91,6 +100,7 @@ void CONN_Task(){
case Finished: // Сессия завершена, ждём окончания и возможного переподключения
// Когда GB/T стейт-машина полностью вернулась в исходное состояние,
// можно считать сессию закрытой и вернуться в Unplugged.
+ cc_enable = 0;
if(CONN_CC_GetState() != GBT_CC_4V){
CONN_SetState(Unplugged);
GBT_Reset();
@@ -111,22 +121,22 @@ void CONN_Task(){
void CONN_SetState(CONN_State_t state){
connectorState = state;
- CONN.connState = state;
+ CONN[0].connState = state;
- if(connectorState == Unknown) EDCAN_printf(LOG_INFO,"Unknown\n");
- if(connectorState == Unplugged) EDCAN_printf(LOG_INFO,"Unplugged\n");
- if(connectorState == Disabled) EDCAN_printf(LOG_INFO,"Disabled\n");
- if(connectorState == Preparing) EDCAN_printf(LOG_INFO,"Preparing\n");
- if(connectorState == AuthRequired) EDCAN_printf(LOG_INFO,"AuthRequired\n");
- if(connectorState == WaitingForEnergy) EDCAN_printf(LOG_INFO,"WaitingForEnergy\n");
- if(connectorState == ChargingPausedEV) EDCAN_printf(LOG_INFO,"ChargingPausedEV\n");
- if(connectorState == ChargingPausedEVSE) EDCAN_printf(LOG_INFO,"ChargingPausedEVSE\n");
- if(connectorState == Charging) EDCAN_printf(LOG_INFO,"Charging\n");
- if(connectorState == AuthTimeout) EDCAN_printf(LOG_INFO,"AuthTimeout\n");
- if(connectorState == Finished) EDCAN_printf(LOG_INFO,"Finished\n");
- if(connectorState == FinishedEVSE) EDCAN_printf(LOG_INFO,"FinishedEVSE\n");
- if(connectorState == FinishedEV) EDCAN_printf(LOG_INFO,"FinishedEV\n");
- if(connectorState == Replugging) EDCAN_printf(LOG_INFO,"Replugging\n");
+ if(connectorState == Unknown) log_printf(LOG_DEBUG,"ConnState: Unknown\n");
+ if(connectorState == Unplugged) log_printf(LOG_DEBUG,"ConnState: Unplugged\n");
+ if(connectorState == Disabled) log_printf(LOG_DEBUG,"ConnState: Disabled\n");
+ if(connectorState == Preparing) log_printf(LOG_DEBUG,"ConnState: Preparing\n");
+ if(connectorState == AuthRequired) log_printf(LOG_DEBUG,"ConnState: AuthRequired\n");
+ if(connectorState == WaitingForEnergy) log_printf(LOG_DEBUG,"ConnState: WaitingForEnergy\n");
+ if(connectorState == ChargingPausedEV) log_printf(LOG_DEBUG,"ConnState: ChargingPausedEV\n");
+ if(connectorState == ChargingPausedEVSE) log_printf(LOG_DEBUG,"ConnState: ChargingPausedEVSE\n");
+ if(connectorState == Charging) log_printf(LOG_DEBUG,"ConnState: Charging\n");
+ if(connectorState == AuthTimeout) log_printf(LOG_DEBUG,"ConnState: AuthTimeout\n");
+ if(connectorState == Finished) log_printf(LOG_DEBUG,"ConnState: Finished\n");
+ if(connectorState == FinishedEVSE) log_printf(LOG_DEBUG,"ConnState: FinishedEVSE\n");
+ if(connectorState == FinishedEV) log_printf(LOG_DEBUG,"ConnState: FinishedEV\n");
+ if(connectorState == Replugging) log_printf(LOG_DEBUG,"ConnState: Replugging\n");
}
diff --git a/Core/Src/cp.c b/Core/Src/cp.c
new file mode 100644
index 0000000..fa4f377
--- /dev/null
+++ b/Core/Src/cp.c
@@ -0,0 +1,194 @@
+#include "cp.h"
+#include "tim.h"
+
+#define CP_CAPTURE_TARGET_CLK_HZ 1000000U
+#define CP_INPUT_SIGNAL_INVERTED 1U
+
+typedef enum {
+ CP_WAIT_RISING_1 = 0,
+ CP_WAIT_FALLING,
+ CP_WAIT_RISING_2
+} CP_CaptureState_t;
+
+static volatile CP_CaptureState_t cp_capture_state = CP_WAIT_RISING_1;
+static volatile uint32_t cp_rise_1 = 0;
+static volatile uint32_t cp_fall = 0;
+static volatile uint32_t cp_rise_2 = 0;
+static volatile uint32_t cp_last_update_ms = 0;
+static volatile CP_Measurement_t cp_measurement = {0, 0, 0};
+
+static uint32_t CP_TicksDiff(uint32_t now, uint32_t prev, uint32_t arr);
+static uint32_t CP_GetTimerClockHz(void);
+static void CP_ApplyStateOutputs(void);
+static uint32_t CP_GetTim3InputClockHz(void);
+
+void CP_Init(void) {
+ TIM_IC_InitTypeDef sConfigIC = {0};
+ uint32_t tim3_input_clk = CP_GetTim3InputClockHz();
+ uint32_t target_prescaler = 0U;
+
+ if (tim3_input_clk > CP_CAPTURE_TARGET_CLK_HZ) {
+ target_prescaler = (tim3_input_clk / CP_CAPTURE_TARGET_CLK_HZ) - 1U;
+ }
+ if (target_prescaler > 0xFFFFU) {
+ target_prescaler = 0xFFFFU;
+ }
+
+ __HAL_TIM_SET_PRESCALER(&htim3, (uint16_t)target_prescaler);
+ __HAL_TIM_SET_COUNTER(&htim3, 0U);
+
+ sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
+ sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
+ sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
+ sConfigIC.ICFilter = 2;
+ HAL_TIM_IC_ConfigChannel(&htim3, &sConfigIC, TIM_CHANNEL_2);
+
+ cp_capture_state = CP_WAIT_RISING_1;
+ cp_measurement.valid = 0;
+ cp_last_update_ms = HAL_GetTick();
+ CP_ApplyStateOutputs();
+ HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_2);
+}
+
+void CP_Task(void) {
+ CP_ApplyStateOutputs();
+
+ if ((HAL_GetTick() - cp_last_update_ms) > 200U) {
+ cp_measurement.valid = 0;
+ cp_measurement.frequency_hz = 0;
+ cp_measurement.duty_percent = 0;
+ }
+}
+
+CP_Measurement_t CP_GetMeasurement(void) {
+ CP_Measurement_t snapshot;
+ __disable_irq();
+ snapshot = cp_measurement;
+ __enable_irq();
+ return snapshot;
+}
+
+void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
+ if ((htim->Instance != TIM3) || (htim->Channel != HAL_TIM_ACTIVE_CHANNEL_2)) {
+ return;
+ }
+
+ uint32_t captured = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
+ uint32_t arr = __HAL_TIM_GET_AUTORELOAD(htim);
+ TIM_RESET_CAPTUREPOLARITY(htim, TIM_CHANNEL_2);
+
+ if (cp_capture_state == CP_WAIT_RISING_1) {
+ cp_rise_1 = captured;
+ cp_capture_state = CP_WAIT_FALLING;
+ TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_FALLING);
+ return;
+ }
+
+ if (cp_capture_state == CP_WAIT_FALLING) {
+ cp_fall = captured;
+ cp_capture_state = CP_WAIT_RISING_2;
+ TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_RISING);
+ return;
+ }
+
+ cp_rise_2 = captured;
+ cp_capture_state = CP_WAIT_RISING_1;
+ TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_2, TIM_INPUTCHANNELPOLARITY_RISING);
+
+ uint32_t period_ticks = CP_TicksDiff(cp_rise_2, cp_rise_1, arr);
+ uint32_t high_ticks = CP_TicksDiff(cp_fall, cp_rise_1, arr);
+ uint32_t timer_clk = CP_GetTimerClockHz();
+
+ if ((period_ticks == 0U) || (high_ticks > period_ticks) || (timer_clk == 0U)) {
+ cp_measurement.valid = 0;
+ return;
+ }
+
+ cp_measurement.frequency_hz = timer_clk / period_ticks;
+ uint32_t duty_high = (high_ticks * 100U + (period_ticks / 2U)) / period_ticks; /* rounded */
+ if (duty_high > 100U) {
+ duty_high = 100U;
+ }
+ uint32_t duty = duty_high;
+#if CP_INPUT_SIGNAL_INVERTED
+ duty = 100U - duty_high;
+#endif
+ cp_measurement.duty_percent = (uint8_t)duty;
+ cp_measurement.valid = 1;
+ cp_last_update_ms = HAL_GetTick();
+}
+
+static uint32_t CP_TicksDiff(uint32_t now, uint32_t prev, uint32_t arr) {
+ if (now >= prev) {
+ return now - prev;
+ }
+ return (arr - prev + 1U) + now;
+}
+
+static uint32_t CP_GetTimerClockHz(void) {
+ uint32_t timclk = CP_GetTim3InputClockHz();
+ uint32_t prescaler = htim3.Instance->PSC;
+ return timclk / (prescaler + 1U);
+}
+
+static uint32_t CP_GetTim3InputClockHz(void) {
+ RCC_ClkInitTypeDef clk_init = {0};
+ uint32_t flash_latency = 0U;
+ uint32_t pclk1 = HAL_RCC_GetPCLK1Freq();
+ HAL_RCC_GetClockConfig(&clk_init, &flash_latency);
+
+ if (clk_init.APB1CLKDivider == RCC_HCLK_DIV1) {
+ return pclk1;
+ }
+ return pclk1 * 2U;
+}
+
+static void CP_ApplyStateOutputs(void) {
+ static CP_State_t last_state = (CP_State_t)0xFF;
+
+ if (last_state == cp_state) {
+ return;
+ }
+
+ switch (cp_state) {
+ case EV_STATE_A_IDLE:
+ HAL_GPIO_WritePin(CP_RELAY_GPIO_Port, CP_RELAY_Pin, GPIO_PIN_RESET);
+ HAL_GPIO_WritePin(CP_STATE_C_GPIO_Port, CP_STATE_C_Pin, GPIO_PIN_RESET);
+ HAL_GPIO_WritePin(CP_STATE_F_GPIO_Port, CP_STATE_F_Pin, GPIO_PIN_RESET);
+ break;
+ case EV_STATE_B_CONN_PREP:
+ HAL_GPIO_WritePin(CP_RELAY_GPIO_Port, CP_RELAY_Pin, GPIO_PIN_SET);
+ HAL_GPIO_WritePin(CP_STATE_C_GPIO_Port, CP_STATE_C_Pin, GPIO_PIN_RESET);
+ HAL_GPIO_WritePin(CP_STATE_F_GPIO_Port, CP_STATE_F_Pin, GPIO_PIN_RESET);
+ break;
+ case EV_STATE_C_CONN_ACTIVE:
+ HAL_GPIO_WritePin(CP_RELAY_GPIO_Port, CP_RELAY_Pin, GPIO_PIN_SET);
+ HAL_GPIO_WritePin(CP_STATE_C_GPIO_Port, CP_STATE_C_Pin, GPIO_PIN_SET);
+ HAL_GPIO_WritePin(CP_STATE_F_GPIO_Port, CP_STATE_F_Pin, GPIO_PIN_RESET);
+ break;
+ case EV_STATE_F_ERROR:
+ HAL_GPIO_WritePin(CP_RELAY_GPIO_Port, CP_RELAY_Pin, GPIO_PIN_SET);
+ HAL_GPIO_WritePin(CP_STATE_C_GPIO_Port, CP_STATE_C_Pin, GPIO_PIN_RESET);
+ HAL_GPIO_WritePin(CP_STATE_F_GPIO_Port, CP_STATE_F_Pin, GPIO_PIN_SET);
+ break;
+
+ case EV_STATE_D_CONN_ACT_VENT:
+ HAL_GPIO_WritePin(CP_RELAY_GPIO_Port, CP_RELAY_Pin, GPIO_PIN_SET);
+ HAL_GPIO_WritePin(CP_STATE_C_GPIO_Port, CP_STATE_C_Pin, GPIO_PIN_SET);
+ HAL_GPIO_WritePin(CP_STATE_F_GPIO_Port, CP_STATE_F_Pin, GPIO_PIN_RESET);
+ break;
+ case EV_STATE_E_NO_POWER:
+ HAL_GPIO_WritePin(CP_RELAY_GPIO_Port, CP_RELAY_Pin, GPIO_PIN_SET);
+ HAL_GPIO_WritePin(CP_STATE_C_GPIO_Port, CP_STATE_C_Pin, GPIO_PIN_RESET);
+ HAL_GPIO_WritePin(CP_STATE_F_GPIO_Port, CP_STATE_F_Pin, GPIO_PIN_SET);
+ break;
+ case EV_STATE_ACQUIRING:
+ default:
+ HAL_GPIO_WritePin(CP_RELAY_GPIO_Port, CP_RELAY_Pin, GPIO_PIN_SET);
+ HAL_GPIO_WritePin(CP_STATE_F_GPIO_Port, CP_STATE_F_Pin, GPIO_PIN_RESET);
+ HAL_GPIO_WritePin(CP_STATE_C_GPIO_Port, CP_STATE_C_Pin, GPIO_PIN_RESET);
+ break;
+ }
+
+ last_state = cp_state;
+}
diff --git a/Core/Src/debug.c b/Core/Src/debug.c
old mode 100755
new mode 100644
index 1050a53..931abe3
--- a/Core/Src/debug.c
+++ b/Core/Src/debug.c
@@ -1,226 +1,182 @@
/*
* debug.c
- *
- * Created on: Apr 16, 2024
- * Author: colorbass
*/
#include "main.h"
#include
#include
+#include
+#include
#include "debug.h"
-#include "board.h"
-#include "charger_gbt.h"
+#include "serial_control.h"
#include "usart.h"
-#include
-#include
+#define DEBUG_BUFFER_SIZE 1024
+#define DEBUG_BUFFER_MAX_COUNT 128
+#define LOG_BUFFER_SIZE 128
-uint8_t debug_rx_buffer[256];
-uint8_t debug_cmd_received;
-uint8_t debug_rx_buffer_size = 0;
+typedef struct {
+ uint8_t buffer[DEBUG_BUFFER_SIZE];
+ volatile uint16_t write_index;
+ volatile uint16_t read_index;
+ volatile uint16_t count;
+} DebugBuffer_t;
-extern UART_HandleTypeDef huart2;
+static DebugBuffer_t debug_buffer = {
+ .buffer = {0},
+ .write_index = 0,
+ .read_index = 0,
+ .count = 0
+};
+
+static uint8_t log_buffer[LOG_BUFFER_SIZE];
+
+static void debug_uart1_write(const uint8_t *data, uint16_t len)
+{
+ /* Best-effort debug mirror to USART1 (PA9/PA10), safe for IRQ context. */
+ for (uint16_t i = 0; i < len; i++) {
+ uint32_t timeout = 10000U;
+ while (((USART1->SR & USART_SR_TXE) == 0U) && (timeout > 0U)) {
+ timeout--;
+ }
+ if (timeout == 0U) {
+ return;
+ }
+ USART1->DR = data[i];
+ }
+}
#if defined(__GNUC__)
int _write(int fd, char * ptr, int len)
{
- HAL_GPIO_WritePin(USART2_DIR_GPIO_Port, USART2_DIR_Pin, 1);
- HAL_UART_Transmit(&huart2, (uint8_t *) ptr, len, HAL_MAX_DELAY);
- HAL_GPIO_WritePin(USART2_DIR_GPIO_Port, USART2_DIR_Pin, 0);
+ (void)fd;
+ debug_buffer_add((const uint8_t*)ptr, (uint16_t)len);
return len;
}
#endif
-void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size){
-
-// if(huart->Instance == USART1){
-// mm_rx_interrupt(huart, Size);
-// }
- if(huart->Instance == USART2){
- debug_rx_interrupt(huart, Size);
+void debug_buffer_add(const uint8_t* data, uint16_t len)
+{
+ debug_uart1_write(data, len);
+ __disable_irq();
+ for (uint16_t i = 0; i < len; i++) {
+ if (debug_buffer.count >= DEBUG_BUFFER_SIZE) {
+ debug_buffer.read_index = (debug_buffer.read_index + 1U) % DEBUG_BUFFER_SIZE;
+ debug_buffer.count--;
+ }
+ debug_buffer.buffer[debug_buffer.write_index] = data[i];
+ debug_buffer.write_index = (debug_buffer.write_index + 1U) % DEBUG_BUFFER_SIZE;
+ debug_buffer.count++;
}
+ __enable_irq();
}
-void debug_rx_interrupt(UART_HandleTypeDef *huart, uint16_t Size){
- debug_rx_buffer[Size] = '\0';
- debug_rx_buffer_size = Size;
- debug_cmd_received = 1;
+uint16_t debug_buffer_available(void)
+{
+ __disable_irq();
+ uint16_t count = debug_buffer.count;
+ __enable_irq();
+ return count;
}
-void debug_init(){
- HAL_UARTEx_ReceiveToIdle_IT(&huart2,debug_rx_buffer,255);
- //mm_schedule_write(0x01, 0x0000, 0x0800);
- // mm_schedule_write(0x02, 0x00FF, 0xFFFF);
- //for (int i=0;i<60;i++)
- // mm_schedule_write(0x02, 0x0000, 0xFF00);
- // mm_schedule_write(0x01, 0x0000, 0x0100);
- // mm_schedule_write(0x01, 0x0000, 0x0100);
-}
-
-void parse_command(uint8_t* buffer, size_t length) {
- // ignore \r \n symbols
- size_t i = 0;
- for (i = 0; i < length; i++) {
- if (buffer[i] == '\r' || buffer[i] == '\n') {
- buffer[i] = '\0';
- length = i;
- break;
- }
- }
- if (buffer[0] == 0) return;
- if (strncmp((const char*)buffer, "reset", length) == 0) {
- printf("Resetting...\n");
- NVIC_SystemReset();
-
- } else if (strncmp((const char*)buffer, "relayaux", length) == 0) {
- printf("Relaying...\n");
- RELAY_Write(RELAY_1, 1);
- HAL_Delay(200);
- RELAY_Write(RELAY_1, 0);
- } else if (strncmp((const char*)buffer, "relaycc", length) == 0) {
- printf("Relaying...\n");
- RELAY_Write(RELAY_CC, 1);
- HAL_Delay(200);
- RELAY_Write(RELAY_CC, 0);
-
-
-// } else if (strncmp((const char*)buffer, "voltage", length) == 0) {
-// printf("Voltaging...\n");
-// mm_schedule_read(0x02, 0x0001);
-
- } else if (strncmp((const char*)buffer, "adc", length) == 0) {
- printf("CC1=%.2f\n", CONN_CC_GetAdc());
-
- // } else if (strncmp((const char*)buffer, "lock_state", length) == 0) {
- // printf("AUX/Lock state=%d\n", GBT_LockGetState());
-
- } else if (strncmp((const char*)buffer, "complete", length) == 0) {
- CONN_SetState(Finished);
-
- } else if (strncmp((const char*)buffer, "start", length) == 0) {
- printf("Started\n");
- GBT_SwitchState(GBT_EV_CONNECTING);
-
- } else if (strncmp((const char*)buffer, "stop", length) == 0) {
- printf("Stopped\n");
- GBT_StopEVSE(GBT_CST_SUSPENDS_ARTIFICIALLY);
-
- } else if (strncmp((const char*)buffer, "stop1", length) == 0) {
- printf("Stopped\n");
- GBT_ForceStop();
-
-// } else if (strncmp((const char*)buffer, "force", length) == 0) {
-// printf("Stopped\n");
-// GBT_Lock(1);
-// GBT_SwitchState(GBT_S2_LOCKED);
-// GBT_Delay(500);
-
- } else if (strncmp((const char*)buffer, "cc_state", length) == 0) {
- switch(CONN_CC_GetState()){
- case GBT_CC_UNKNOWN:
- printf("GBT_CC_UNKNOWN\n");
- break;
- case GBT_CC_12V:
- printf("GBT_CC_12V\n");
- break;
- case GBT_CC_6V:
- printf("GBT_CC_6V\n");
- break;
- case GBT_CC_4V:
- printf("GBT_CC_4V\n");
- break;
- case GBT_CC_2V:
- printf("GBT_CC_2V\n");
- break;
-
- }
- } else if (strncmp((const char*)buffer, "temp", length) == 0) {
- printf("temp1 %d\n",GBT_ReadTemp(0));
- printf("temp2 %d\n",GBT_ReadTemp(1));
- } else if (strncmp((const char*)buffer, "info1", length) == 0) {
- printf("Battery info:\n");
- printf("maxCV %dV\n",GBT_BATStat.maxCellVoltage/100); // 0.01v/bit
- printf("maxCC %dA\n",GBT_BATStat.maxChargingCurrent/10); // 0.1A/bit
- printf("totE %dkWh\n",GBT_BATStat.totalEnergy/10); // 0.1kWh
- printf("maxCV %dV\n",GBT_BATStat.maxChargingVoltage/10); // 0.1V/ bit
- printf("maxT %dC\n",(int16_t)GBT_BATStat.maxTemp-50); // 1C/bit, -50C offset
- printf("SOC %dp\n",GBT_BATStat.SOC/10); // 0.1%/bit , 0..100%
- printf("Volt. %dV\n",GBT_BATStat.measVoltage/10); // 0.1V/bit
-
- } else if (strncmp((const char*)buffer, "info2", length) == 0) {
- printf("EV info:\n");
- printf("GBT_ver V%d.%d%d\n",GBT_EVInfo.version[0],GBT_EVInfo.version[1],GBT_EVInfo.version[2]);
- printf("Battery type: %d\n",GBT_EVInfo.batteryType);
- printf("Battery capacity: %d\n", GBT_EVInfo.batteryCapacity); // 0.1Ah/bit
- printf("Battery voltage: %d\n", GBT_EVInfo.batteryVoltage); // 0.1V/bit
- printf("Battery vendor: %.4s\n", GBT_EVInfo.batteryVendor); // Battery vendor (ASCII string)
- printf("Battery SN: %lu\n", GBT_EVInfo.batterySN); // int
- printf("Battery manufacture date: %02d.%02d.%04d\n", GBT_EVInfo.batteryManuD, GBT_EVInfo.batteryManuM ,GBT_EVInfo.batteryManuY+1985); // year (offset 1985)
- printf("Battery cycles: %d\n", GBT_EVInfo.batteryCycleCount); //uint24_t
- printf("Own auto: %d\n", GBT_EVInfo.ownAuto); // 0 = lizing, 1 = own auto
- printf("EVIN: %.17s\n", GBT_EVInfo.EVIN); //EVIN
- printf("EV_SW_VER: %.8s\n", GBT_EVInfo.EV_SW_VER);
-
- } else if (strncmp((const char*)buffer, "info3", length) == 0) {
- printf("GBT_MaxLoad info:\n");
- printf("Output max current: %d\n",GBT_MaxLoad.maxOutputCurrent);
- printf("Output min current: %d\n",GBT_MaxLoad.minOutputCurrent);
- printf("Output max voltage: %d\n",GBT_MaxLoad.maxOutputVoltage);
- printf("Output min voltage: %d\n",GBT_MaxLoad.minOutputVoltage);
- printf("\nGBT_ChargerInfo info:\n");
- printf("BMS Recognized: %d\n",GBT_ChargerInfo.bmsIdentified);
- printf("Charger location: %.3s\n",GBT_ChargerInfo.chargerLocation);
- printf("Charger number: %lu\n",GBT_ChargerInfo.chargerNumber);
-
-
- } else if (strncmp((const char*)buffer, "help", length) == 0) {
- printf("Command list:\n");
- printf("reset\n");
- printf("help\n");
- printf("cc_state\n");
- printf("lock_state\n");
- printf("adc\n");
- printf("relay(cc,aux)\n");
- printf("start\n");
- printf("stop\n");
- printf("stop1\n");
-// printf("force\n");
- printf("temp\n");
- printf("info1\n");
- printf("info2\n");
- printf("info3\n");
- printf("time\n");
- printf("cantest\n");
-
- //TODO: info commands
-
- } else if (strncmp((const char*)buffer, "time", length) == 0) {
-
- time_t unix_time = (time_t)get_Current_Time();
- struct tm *parts = localtime(&unix_time);
-
- printf("Year: %d\n", parts->tm_year + 1900);
- printf("Month: %d\n", parts->tm_mon + 1);
- printf("Day: %d\n", parts->tm_mday);
- printf("Hour: %d\n", parts->tm_hour);
- printf("Minute: %d\n", parts->tm_min);
- printf("Second: %d\n", parts->tm_sec);
-
- } else if (strncmp((const char*)buffer, "cantest", length) == 0) {
- //GBT_SendCHM();
- GBT_Error(0xFDF0C0FC); //BRM Timeout
- printf("can test\n");
-
- } else {
- printf("Unknown command\n");
- }
-}
-
-void debug_task(){
- if(debug_cmd_received){
- parse_command(debug_rx_buffer, debug_rx_buffer_size);
- HAL_UARTEx_ReceiveToIdle_IT(&huart2,debug_rx_buffer,255);
- debug_cmd_received = 0;
+void debug_buffer_send(void)
+{
+ __disable_irq();
+ if (debug_buffer.count == 0U) {
+ __enable_irq();
+ return;
}
+
+ uint16_t bytes_to_send = debug_buffer.count;
+ if (bytes_to_send > DEBUG_BUFFER_MAX_COUNT) {
+ bytes_to_send = DEBUG_BUFFER_MAX_COUNT;
+ }
+
+ uint16_t bytes_to_end = DEBUG_BUFFER_SIZE - debug_buffer.read_index;
+ if (bytes_to_send > bytes_to_end) {
+ bytes_to_send = bytes_to_end;
+ }
+
+ if (bytes_to_send == debug_buffer.count) {
+ SC_SendPacket(&debug_buffer.buffer[debug_buffer.read_index], bytes_to_send, CMD_GET_LOG);
+ } else {
+ SC_SendPacket(&debug_buffer.buffer[debug_buffer.read_index], bytes_to_send, CMD_GET_LOG_CONTINUE);
+ }
+
+ debug_buffer.read_index = (debug_buffer.read_index + bytes_to_send) % DEBUG_BUFFER_SIZE;
+ debug_buffer.count -= bytes_to_send;
+ __enable_irq();
+}
+
+int log_printf(int level, const char *format, ...)
+{
+ va_list args;
+ int result;
+ const char *tag;
+ int written;
+ EDCAN_LogLevel_t current_level;
+ EDCAN_LogLevel_t msg_level;
+
+ if(level < LOG_EMERG || level > LOG_DEBUG){
+ return 0;
+ }
+ msg_level = (EDCAN_LogLevel_t)level;
+ current_level = EDCAN_GetLogLevel();
+ if(msg_level > current_level){
+ return 0;
+ }
+
+ switch(level){
+ case LOG_EMERG:
+ tag = "[EMR] ";
+ break;
+ case LOG_ALERT:
+ tag = "[ALT] ";
+ break;
+ case LOG_CRIT:
+ tag = "[CRT] ";
+ break;
+ case LOG_ERR:
+ tag = "[ERR] ";
+ break;
+ case LOG_WARN:
+ tag = "[WRN] ";
+ break;
+ case LOG_NOTICE:
+ tag = "[NTC] ";
+ break;
+ case LOG_INFO:
+ tag = "[INF] ";
+ break;
+ case LOG_DEBUG:
+ tag = "[DBG] ";
+ break;
+ default:
+ tag = "[LOG] ";
+ break;
+ }
+
+ log_buffer[0] = (uint8_t)level;
+ written = snprintf((char*)&log_buffer[1], LOG_BUFFER_SIZE - 2, "EV %s", tag);
+ if(written < 0){
+ return written;
+ }
+ if(written >= (LOG_BUFFER_SIZE - 2)){
+ written = LOG_BUFFER_SIZE - 2;
+ }
+
+ va_start(args, format);
+ result = vsnprintf((char*)&log_buffer[1 + written], LOG_BUFFER_SIZE - 2 - written, format, args);
+ va_end(args);
+
+ if (result < 0) {
+ return result;
+ }
+ if (result >= (LOG_BUFFER_SIZE - 2 - written)) {
+ result = LOG_BUFFER_SIZE - 2 - written;
+ }
+
+ log_buffer[1 + written + result] = '\0';
+ debug_buffer_add(log_buffer, (uint16_t)(2 + written + result));
+ return result + written;
}
diff --git a/Core/Src/gbt_packet.c b/Core/Src/gbt_packet.c
index 442703a..064a7df 100755
--- a/Core/Src/gbt_packet.c
+++ b/Core/Src/gbt_packet.c
@@ -50,6 +50,11 @@ void GBT_SendBSM(void){
J_SendPacket(0x1300, 6, sizeof(GBT_BatteryStatus), (uint8_t*)&GBT_BatteryStatus);
}
+// BST: запрос остановки зарядки со стороны EV
+void GBT_SendBST(uint32_t causeCode){
+ J_SendPacket(0x1900, 6, sizeof(causeCode), (uint8_t*)&causeCode);
+}
+
// BSD: статус батареи при завершении
void GBT_SendBSD(void){
J_SendPacket(0x1C00, 6, sizeof(GBT_BATStat), (uint8_t*)&GBT_BATStat);
diff --git a/Core/Src/gpio.c b/Core/Src/gpio.c
index d5b287b..4923abb 100644
--- a/Core/Src/gpio.c
+++ b/Core/Src/gpio.c
@@ -54,14 +54,14 @@ void MX_GPIO_Init(void)
__HAL_RCC_GPIOD_CLK_ENABLE();
/*Configure GPIO pin Output Level */
- HAL_GPIO_WritePin(GPIOC, LOCK_A_Pin|LOCK_B_Pin, GPIO_PIN_RESET);
+ HAL_GPIO_WritePin(GPIOC, CP_STATE_F_Pin|CP_RELAY_Pin|LOCK_A_Pin|LOCK_B_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
- HAL_GPIO_WritePin(GPIOE, RELAY5_Pin|RELAY4_Pin|RELAY3_Pin|RELAY2_Pin
- |RELAY1_Pin, GPIO_PIN_RESET);
+ HAL_GPIO_WritePin(GPIOA, CP_STATE_C_Pin|RELAY_CC_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
- HAL_GPIO_WritePin(RELAY_CC_GPIO_Port, RELAY_CC_Pin, GPIO_PIN_RESET);
+ HAL_GPIO_WritePin(GPIOE, RELAY1_Pin|RELAY2_Pin|RELAY3_Pin|RELAY4_Pin
+ |RELAY5_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOD, RELAY_DC_Pin|USART2_DIR_Pin, GPIO_PIN_RESET);
@@ -69,18 +69,25 @@ void MX_GPIO_Init(void)
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(EE_WP_GPIO_Port, EE_WP_Pin, GPIO_PIN_RESET);
+ /*Configure GPIO pins : CP_STATE_F_Pin CP_RELAY_Pin LOCK_A_Pin LOCK_B_Pin */
+ GPIO_InitStruct.Pin = CP_STATE_F_Pin|CP_RELAY_Pin|LOCK_A_Pin|LOCK_B_Pin;
+ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+ HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
+
/*Configure GPIO pins : IN_SW0_Pin IN_SW1_Pin */
GPIO_InitStruct.Pin = IN_SW0_Pin|IN_SW1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
- /*Configure GPIO pins : LOCK_A_Pin LOCK_B_Pin */
- GPIO_InitStruct.Pin = LOCK_A_Pin|LOCK_B_Pin;
+ /*Configure GPIO pins : CP_STATE_C_Pin RELAY_CC_Pin */
+ GPIO_InitStruct.Pin = CP_STATE_C_Pin|RELAY_CC_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
- HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
+ HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pins : IN0_Pin AC_OK_Pin ISO_IN_Pin */
GPIO_InitStruct.Pin = IN0_Pin|AC_OK_Pin|ISO_IN_Pin;
@@ -88,22 +95,15 @@ void MX_GPIO_Init(void)
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
- /*Configure GPIO pins : RELAY5_Pin RELAY4_Pin RELAY3_Pin RELAY2_Pin
- RELAY1_Pin */
- GPIO_InitStruct.Pin = RELAY5_Pin|RELAY4_Pin|RELAY3_Pin|RELAY2_Pin
- |RELAY1_Pin;
+ /*Configure GPIO pins : RELAY1_Pin RELAY2_Pin RELAY3_Pin RELAY4_Pin
+ RELAY5_Pin */
+ GPIO_InitStruct.Pin = RELAY1_Pin|RELAY2_Pin|RELAY3_Pin|RELAY4_Pin
+ |RELAY5_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
- /*Configure GPIO pin : RELAY_CC_Pin */
- GPIO_InitStruct.Pin = RELAY_CC_Pin;
- GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
- HAL_GPIO_Init(RELAY_CC_GPIO_Port, &GPIO_InitStruct);
-
/*Configure GPIO pins : RELAY_DC_Pin USART2_DIR_Pin */
GPIO_InitStruct.Pin = RELAY_DC_Pin|USART2_DIR_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
diff --git a/Core/Src/j1939.c b/Core/Src/j1939.c
index 50358ce..73a58b6 100755
--- a/Core/Src/j1939.c
+++ b/Core/Src/j1939.c
@@ -11,107 +11,272 @@
#include "string.h"
#include "can.h"
#include "edcan.h"
+#include "debug.h"
+#include
extern GBT_BCL_t GBT_ReqPower;
extern GBT_BCL_t GBT_CurrPower;
j_receive_t j_rx;
-void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
-{
- CAN_RxHeaderTypeDef RxHeader;
- uint8_t RxData[8] = {0,};
+typedef struct{
+ uint8_t data[256];
+ uint32_t PGN;
+ uint16_t size;
+ uint8_t packets;
+ uint8_t next_packet;
+ uint8_t step;
+ uint8_t state; // 0=idle, 1=wait CTS, 2=wait ACK
+ uint32_t tick;
+}j_transmit_t;
- if(HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, RxData) == HAL_OK)
- {
- if((RxHeader.ExtId & 0x00FFFF) == ((J_ID_EV << 8) | J_ID_SE)){ // SA, DA match
- switch ((RxHeader.ExtId>>8) & 0x00FF00){
+static j_transmit_t j_tx;
- case 0xEC00: //PGN Connection Management Message
- if(RxData[0] == 16){ //Request to Send
- /* Set the RTS values */
- j_rx.size = RxData[1] | (RxData[2]<<8);
- j_rx.packet = 1;
- j_rx.packets = RxData[3];
- j_rx.step = 2; //TODO
- j_rx.step_cts_remain = j_rx.step;
- j_rx.PGN = (RxData[7] << 16) | (RxData[6] << 8) | RxData[5];
- if(j_rx.size<256) { //TODO: valid check
- J_SendCTS(j_rx);
- j_rx.state = 1;
- }
- }
- if(RxData[0] == 255){ //Connection Abort
- j_rx.state = 0;
- }
+#define J1939_BUFFER_SIZE 64U
- //if(RxData[0] == 32){}//Broadcast Announce Message
- /*
- * 1CEC56F4 10 31 00 07 07 00 02 00
- * 1CECF456 11 02 01 FF FF 00 02 00
- * 1CEB56F4 01 01 01 00 03 46 05 40
- * 1CEC56F4 FF FF FF FF FF 00 00 00
- */
+typedef struct {
+ j1939_rx_frame_t buffer[J1939_BUFFER_SIZE];
+ uint16_t head;
+ uint16_t tail;
+ uint16_t count;
+ uint32_t overflow;
+} j1939_rx_ring_t;
- break;
+typedef struct {
+ j1939_tx_frame_t buffer[J1939_BUFFER_SIZE];
+ uint16_t head;
+ uint16_t tail;
+ uint16_t count;
+ uint8_t busy;
+ uint32_t overflow;
+} j1939_tx_ring_t;
- case 0xEB00: //PGN Data Message
- if(j_rx.state != 1) break;
- if((RxData[0]>0) && (RxData[0]<35)){ //Array limit check
- if(j_rx.packet == RxData[0]){ //step check
- memcpy (&j_rx.data[(RxData[0]-1)*7], &RxData[1],7);
- j_rx.packet++;
- if(j_rx.packet > j_rx.packets){
- //End of transmission
- J_SendACK(j_rx);
+static j1939_rx_ring_t j_rxbuf;
+static j1939_tx_ring_t j_txbuf;
+static uint32_t j_tx_watchdog_last_log_tick;
- j_rx.state = 2;
- }else{
- if(j_rx.step_cts_remain > 0) j_rx.step_cts_remain--;
- if(j_rx.step_cts_remain == 0){
- J_SendCTS(j_rx);
- j_rx.step_cts_remain = 2;
- }
- }
- }
- }
- break;
+#define J1939_CRITICAL_ENTER() __disable_irq()
+#define J1939_CRITICAL_EXIT() __enable_irq()
- case 0x1E00: //PGN BEM (ERROR)
- //Error force stop
- // --> Suspend EV
- EDCAN_printf(LOG_WARN, "BEM Received, force stopping...\n");
- EDCAN_printf(LOG_WARN, "BEM: %02X %02X %02X %02X", RxData[0], RxData[1], RxData[2], RxData[3]);
- EDCAN_printf(LOG_WARN, " %02X %02X %02X %02X\n", RxData[4], RxData[5], RxData[6], RxData[7]);
- GBT_ForceStop();
- break;
+static void J_SendTpRts(void);
+static void J_SendTpDtRange(uint8_t start_packet, uint8_t count);
+static void J_TxCheckTimeout(void);
+static void J_TxReset(void);
+static void J1939_ProcessRxFrame(const j1939_rx_frame_t *frame);
+static void J1939_RxBufferAdd(const j1939_rx_frame_t *frame);
+static uint8_t J1939_RxBufferGet(j1939_rx_frame_t *frame);
+static void J1939_TxBufferAdd(const j1939_tx_frame_t *frame);
+static uint8_t J1939_TxBufferPeek(j1939_tx_frame_t *frame);
+static void J1939_TxBufferDropFirst(void);
+static void J1939_TxQueueByPgn(uint32_t PGN, uint8_t pri, uint8_t DLC, const uint8_t *data, uint8_t pad_ff);
- case 0x1900: //PGN BST (STOP)
- //Normal stop
+#define J1939_TP_CTS_WAIT_TIMEOUT_MS 1000U
+#define J1939_TP_ACK_WAIT_TIMEOUT_MS 1000U
- // --> Suspend EV
- EDCAN_printf(LOG_WARN, "BST Received, stopping...\n");
- EDCAN_printf(LOG_WARN, "BST: %02X %02X %02X %02X", RxData[0], RxData[1], RxData[2], RxData[3]);
- EDCAN_printf(LOG_WARN, " %02X %02X %02X %02X\n", RxData[4], RxData[5], RxData[6], RxData[7]);
- GBT_StopEV(GBT_CST_BMS_ACTIVELY_SUSPENDS);
+static void J_TxReset(void){
+ if(j_tx.state != 0){
+ log_printf(LOG_WARN, "J1939 chunk send failed: TX session reset (state=%u pgn=0x%lX next=%u/%u)\n",
+ j_tx.state, j_tx.PGN, j_tx.next_packet, j_tx.packets);
+ }
+ memset(&j_tx, 0, sizeof(j_tx));
+}
- break;
+void J1939_InitBuffers(void){
+ memset(&j_rxbuf, 0, sizeof(j_rxbuf));
+ memset(&j_txbuf, 0, sizeof(j_txbuf));
+ j_tx_watchdog_last_log_tick = 0U;
+ J_TxReset();
+}
- default:
- if(j_rx.state == 0){//TODO protections
- //Short packet
- j_rx.size = RxHeader.DLC;
- j_rx.packet = 1;
- j_rx.packets = 1;
- j_rx.step = 1;
- j_rx.step_cts_remain = 0;
- j_rx.PGN = (RxHeader.ExtId>>8) & 0x00FF00;
- j_rx.state = 2;
- memcpy (j_rx.data, RxData, j_rx.size);
- }
- }
- }
- }
+uint16_t J1939_GetRxBufferCount(void){
+ uint16_t c;
+ J1939_CRITICAL_ENTER();
+ c = j_rxbuf.count;
+ J1939_CRITICAL_EXIT();
+ return c;
+}
+
+uint16_t J1939_GetTxBufferCount(void){
+ uint16_t c;
+ J1939_CRITICAL_ENTER();
+ c = j_txbuf.count;
+ J1939_CRITICAL_EXIT();
+ return c;
+}
+
+uint32_t J1939_GetRxOverflowCount(void){
+ return j_rxbuf.overflow;
+}
+
+uint32_t J1939_GetTxOverflowCount(void){
+ return j_txbuf.overflow;
+}
+
+void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan){
+ j1939_rx_frame_t frame;
+ CAN_RxHeaderTypeDef rx_header;
+ uint8_t rx_data[8] = {0};
+
+ if(HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rx_header, rx_data) != HAL_OK) return;
+
+ frame.ExtId = rx_header.ExtId;
+ frame.DLC = rx_header.DLC;
+ frame.tick = HAL_GetTick();
+ memcpy(frame.data, rx_data, sizeof(frame.data));
+ J1939_RxBufferAdd(&frame);
+}
+
+static void J1939_ProcessRxFrame(const j1939_rx_frame_t *frame){
+ uint32_t pgn;
+
+ if((frame->ExtId & 0x00FFFF) != ((J_ID_EV << 8) | J_ID_SE)) return; // SA, DA match
+
+ switch ((frame->ExtId >> 8) & 0x00FF00){
+ case 0xEC00:
+ if(frame->data[0] == 16){ // RTS
+ j_rx.size = frame->data[1] | (frame->data[2] << 8);
+ j_rx.packet = 1;
+ j_rx.packets = frame->data[3];
+ j_rx.step = 2;
+ j_rx.step_cts_remain = j_rx.step;
+ j_rx.PGN = (frame->data[7] << 16) | (frame->data[6] << 8) | frame->data[5];
+ if(j_rx.size < 256){
+ J_SendCTS(j_rx);
+ j_rx.state = 1;
+ }
+ }
+ if(frame->data[0] == 17){ // CTS
+ pgn = (frame->data[7] << 16) | (frame->data[6] << 8) | frame->data[5];
+ if((j_tx.state == 1) && (pgn == j_tx.PGN)){
+ uint8_t req_count = frame->data[1];
+ uint8_t req_start_packet = frame->data[2];
+ log_printf(LOG_DEBUG, "J1939 event: TP CTS received (pgn=0x%lX cnt=%u start=%u exp=%u)\n",
+ pgn, req_count, req_start_packet, j_tx.next_packet);
+ if(req_count == 0){
+ log_printf(LOG_DEBUG, "J1939 event: TP CTS wait (pgn=0x%lX)\n", j_tx.PGN);
+ }else{
+ j_tx.tick = frame->tick;
+ J_SendTpDtRange(req_start_packet, req_count);
+ }
+ }else{
+ log_printf(LOG_WARN, "J1939 chunk send failed: CTS ignored (tx_state=%u tx_pgn=0x%lX rx_pgn=0x%lX)\n",
+ j_tx.state, j_tx.PGN, pgn);
+ }
+ }
+ if(frame->data[0] == 19){ // ACK
+ pgn = (frame->data[7] << 16) | (frame->data[6] << 8) | frame->data[5];
+ if((j_tx.state == 2) && (pgn == j_tx.PGN)){
+ log_printf(LOG_DEBUG, "J1939 event: TP ACK received, TX complete (pgn=0x%lX)\n", pgn);
+ j_tx.state = 0;
+ }
+ }
+ if(frame->data[0] == 255){
+ j_rx.state = 0;
+ J_TxReset();
+ }
+ break;
+
+ case 0xEB00:
+ if(j_rx.state != 1) return;
+ if((frame->data[0] > 0) && (frame->data[0] < 35) && (j_rx.packet == frame->data[0])){
+ memcpy(&j_rx.data[(frame->data[0]-1)*7], &frame->data[1], 7);
+ j_rx.packet++;
+ if(j_rx.packet > j_rx.packets){
+ J_SendACK(j_rx);
+ j_rx.state = 2;
+ }else{
+ if(j_rx.step_cts_remain > 0) j_rx.step_cts_remain--;
+ if(j_rx.step_cts_remain == 0){
+ J_SendCTS(j_rx);
+ j_rx.step_cts_remain = 2;
+ }
+ }
+ }
+ break;
+
+ case 0x1E00:
+ log_printf(LOG_WARN, "J1939 fault received: BEM, forcing stop (data=%02X %02X %02X %02X %02X %02X %02X %02X)\n",
+ frame->data[0], frame->data[1], frame->data[2], frame->data[3],
+ frame->data[4], frame->data[5], frame->data[6], frame->data[7]);
+ GBT_ForceStop();
+ break;
+
+ case 0x1900:
+ /* Repeated BST frames during STOP flow are normal on the bus.
+ * Handle/log only once to avoid flooding UART logs.
+ */
+ if((GBT_State != GBT_STOP) && (GBT_State != GBT_STOP_CSD) && (GBT_State != GBT_COMPLETE)){
+ log_printf(LOG_DEBUG, "J1939 event: BST received, initiating stop flow (data=%02X %02X %02X %02X %02X %02X %02X %02X)\n",
+ frame->data[0], frame->data[1], frame->data[2], frame->data[3],
+ frame->data[4], frame->data[5], frame->data[6], frame->data[7]);
+ GBT_StopEV(GBT_CST_BMS_ACTIVELY_SUSPENDS);
+ }
+ break;
+
+ default:
+ if(j_rx.state == 0){
+ j_rx.size = frame->DLC;
+ j_rx.packet = 1;
+ j_rx.packets = 1;
+ j_rx.step = 1;
+ j_rx.step_cts_remain = 0;
+ j_rx.PGN = (frame->ExtId >> 8) & 0x00FF00;
+ j_rx.state = 2;
+ memcpy(j_rx.data, frame->data, j_rx.size);
+ }
+ break;
+ }
+}
+
+void J1939_ExchangeRxBuffer(void){
+ j1939_rx_frame_t frame;
+ J_TxCheckTimeout();
+ if(J1939_RxBufferGet(&frame)){
+ J1939_ProcessRxFrame(&frame);
+ }
+}
+
+void J1939_ExchangeTxBuffer(void){
+ j1939_tx_frame_t frame;
+ CAN_TxHeaderTypeDef tx_header;
+ uint32_t tx_mailbox;
+ HAL_StatusTypeDef tx_status;
+
+ if(HAL_CAN_GetTxMailboxesFreeLevel(&hcan1) == 0) return;
+
+ /* Atomically reserve first queued frame without holding IRQ over HAL call */
+ J1939_CRITICAL_ENTER();
+ if(j_txbuf.busy || (j_txbuf.count == 0U)){
+ J1939_CRITICAL_EXIT();
+ return;
+ }
+ j_txbuf.busy = 1U;
+ frame = j_txbuf.buffer[j_txbuf.tail];
+ J1939_CRITICAL_EXIT();
+
+ tx_header.ExtId = frame.ExtId;
+ tx_header.RTR = CAN_RTR_DATA;
+ tx_header.IDE = CAN_ID_EXT;
+ tx_header.DLC = frame.DLC;
+
+ tx_status = HAL_CAN_AddTxMessage(&hcan1, &tx_header, frame.data, &tx_mailbox);
+
+ J1939_CRITICAL_ENTER();
+ if((tx_status == HAL_OK) && (j_txbuf.count > 0U)){
+ j_txbuf.tail = (j_txbuf.tail + 1U) % J1939_BUFFER_SIZE;
+ j_txbuf.count--;
+ }
+ j_txbuf.busy = 0U;
+ J1939_CRITICAL_EXIT();
+
+ if(tx_status != HAL_OK){
+ log_printf(LOG_WARN, "J1939 send failed: CAN TX error (st=%d extid=0x%lX dlc=%u free_mb=%lu err=0x%lX)\n",
+ (int)tx_status, frame.ExtId, frame.DLC, HAL_CAN_GetTxMailboxesFreeLevel(&hcan1), HAL_CAN_GetError(&hcan1));
+ if((tx_status == HAL_ERROR) && (HAL_CAN_GetError(&hcan1) & HAL_CAN_ERROR_NOT_INITIALIZED)){
+ log_printf(LOG_WARN, "J1939 send failed: CAN not initialized, reinitializing\n");
+ GBT_CAN_ReInit();
+ }
+ }
}
void GBT_CAN_ReInit(){
@@ -120,24 +285,119 @@ void GBT_CAN_ReInit(){
HAL_CAN_Start(&hcan1);
HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
GBT_CAN_FilterInit();
+ J1939_InitBuffers();
}
void J_SendPacket(uint32_t PGN, uint8_t pri, uint8_t DLC, uint8_t *data){
+ J_TxCheckTimeout();
- CAN_TxHeaderTypeDef tx_header;
- uint32_t tx_mailbox;
+ if(DLC > 8){
+ /* Transport protocol for multi-packet payloads */
+ if(DLC > sizeof(j_tx.data)) return;
+ if(j_tx.state != 0){
+ log_printf(LOG_WARN, "J1939 chunk send failed: TX busy (state=%u req_pgn=0x%lX cur_pgn=0x%lX)\n",
+ j_tx.state, PGN, j_tx.PGN);
+ return;
+ }
- tx_header.ExtId = (pri << 26) | (PGN << 8) | (J_ID_SE << 8) | J_ID_EV;
- tx_header.RTR = CAN_RTR_DATA;
- tx_header.IDE = CAN_ID_EXT;
- tx_header.DLC = DLC;
+ memset(&j_tx, 0, sizeof(j_tx));
+ memcpy(j_tx.data, data, DLC);
+ j_tx.PGN = PGN;
+ j_tx.size = DLC;
+ j_tx.packets = (DLC + 6) / 7;
+ j_tx.next_packet = 1;
+ j_tx.step = 2;
+ j_tx.state = 1;
+ j_tx.tick = HAL_GetTick();
+ log_printf(LOG_DEBUG, "J1939 event: TP RTS sent (pgn=0x%lX size=%u packets=%u)\n",
+ j_tx.PGN, j_tx.size, j_tx.packets);
- //TODO buffer wait
- HAL_CAN_AddTxMessage(&hcan1, &tx_header, data, &tx_mailbox);
- //HAL_Delay(2);
+ J_SendTpRts();
+ return;
+ }
+ J1939_TxQueueByPgn(PGN, pri, DLC, data, 1);
}
+static void J_TxCheckTimeout(void){
+ if(j_tx.state != 0){
+ uint32_t now = HAL_GetTick();
+ if((now - j_tx_watchdog_last_log_tick) >= 500U){
+ log_printf(LOG_DEBUG, "J1939 event: TP TX watchdog (state=%u pgn=0x%lX next=%u/%u age=%lu)\n",
+ j_tx.state, j_tx.PGN, j_tx.next_packet, j_tx.packets, (now - j_tx.tick));
+ j_tx_watchdog_last_log_tick = now;
+ }
+ }else{
+ j_tx_watchdog_last_log_tick = HAL_GetTick();
+ }
+
+ if((j_tx.state == 1) && ((HAL_GetTick() - j_tx.tick) > J1939_TP_CTS_WAIT_TIMEOUT_MS)){
+ log_printf(LOG_WARN, "J1939 chunk send failed: CTS timeout (pgn=0x%lX), resetting TX session\n", j_tx.PGN);
+ J_TxReset();
+ }else if((j_tx.state == 2) && ((HAL_GetTick() - j_tx.tick) > J1939_TP_ACK_WAIT_TIMEOUT_MS)){
+ log_printf(LOG_WARN, "J1939 chunk send failed: ACK timeout (pgn=0x%lX), resetting TX session\n", j_tx.PGN);
+ J_TxReset();
+ }
+}
+
+static void J_SendTpRts(void){
+ uint8_t data[8];
+
+ data[0] = 16; // CONTROL_BYTE_TP_CM_RTS
+ data[1] = j_tx.size & 0xFF;
+ data[2] = j_tx.size >> 8;
+ data[3] = j_tx.packets;
+ data[4] = j_tx.step; // max packets before next CTS
+ data[5] = j_tx.PGN;
+ data[6] = j_tx.PGN >> 8;
+ data[7] = j_tx.PGN >> 16;
+
+ J1939_TxQueueByPgn(0x00EC00, 7, 8, data, 0);
+}
+
+static void J_SendTpDtRange(uint8_t start_packet, uint8_t count){
+ uint8_t dt[8];
+ uint8_t packet;
+ uint8_t i;
+ uint16_t idx;
+
+ if(j_tx.state != 1){
+ log_printf(LOG_WARN, "J1939 chunk send failed: TP DT ignored (invalid TX state=%u)\n", j_tx.state);
+ return;
+ }
+
+ if((start_packet == 0) || (start_packet > j_tx.packets)) return;
+ if(count == 0) return;
+ if(start_packet != j_tx.next_packet){
+ log_printf(LOG_WARN, "J1939 chunk send failed: TP desync (start=%u expected=%u), resetting TX session\n", start_packet, j_tx.next_packet);
+ J_TxReset();
+ return;
+ }
+ if((start_packet + count - 1) > j_tx.packets){
+ count = j_tx.packets - start_packet + 1;
+ }
+
+ for(packet = 0; packet < count; packet++){
+ uint8_t seq = start_packet + packet;
+ dt[0] = seq;
+ idx = (uint16_t)(seq - 1) * 7;
+ for(i = 0; i < 7; i++){
+ if((idx + i) < j_tx.size) dt[i + 1] = j_tx.data[idx + i];
+ else dt[i + 1] = 0xFF;
+ }
+ J1939_TxQueueByPgn(0x00EB00, 7, 8, dt, 0);
+ }
+ log_printf(LOG_DEBUG, "J1939 event: TP DT sent (pgn=0x%lX start=%u cnt=%u)\n", j_tx.PGN, start_packet, count);
+
+ j_tx.next_packet = start_packet + count;
+ j_tx.tick = HAL_GetTick();
+ if(j_tx.next_packet > j_tx.packets){
+ j_tx.state = 2; // wait ACK
+ }else{
+ j_tx.state = 1; // wait next CTS
+ }
+}
+
//void J_SendPacketLong(){
// //TODO (no need)
//}
@@ -195,3 +455,77 @@ void GBT_CAN_FilterInit(){
}
}
+
+static void J1939_RxBufferAdd(const j1939_rx_frame_t *frame){
+ J1939_CRITICAL_ENTER();
+ j_rxbuf.buffer[j_rxbuf.head] = *frame;
+ j_rxbuf.head = (j_rxbuf.head + 1U) % J1939_BUFFER_SIZE;
+ if(j_rxbuf.count == J1939_BUFFER_SIZE){
+ j_rxbuf.tail = (j_rxbuf.tail + 1U) % J1939_BUFFER_SIZE;
+ j_rxbuf.overflow++;
+ log_printf(LOG_WARN, "J1939 RX buffer overflow: dropped oldest frame, overflow_count=%lu\n", j_rxbuf.overflow);
+ }else{
+ j_rxbuf.count++;
+ }
+ J1939_CRITICAL_EXIT();
+}
+
+static uint8_t J1939_RxBufferGet(j1939_rx_frame_t *frame){
+ uint8_t ok = 0;
+ J1939_CRITICAL_ENTER();
+ if(j_rxbuf.count > 0){
+ *frame = j_rxbuf.buffer[j_rxbuf.tail];
+ j_rxbuf.tail = (j_rxbuf.tail + 1U) % J1939_BUFFER_SIZE;
+ j_rxbuf.count--;
+ ok = 1;
+ }
+ J1939_CRITICAL_EXIT();
+ return ok;
+}
+
+static void J1939_TxBufferAdd(const j1939_tx_frame_t *frame){
+ J1939_CRITICAL_ENTER();
+ j_txbuf.buffer[j_txbuf.head] = *frame;
+ j_txbuf.head = (j_txbuf.head + 1U) % J1939_BUFFER_SIZE;
+ if(j_txbuf.count == J1939_BUFFER_SIZE){
+ j_txbuf.tail = (j_txbuf.tail + 1U) % J1939_BUFFER_SIZE;
+ j_txbuf.overflow++;
+ log_printf(LOG_WARN, "J1939 TX buffer overflow: dropped oldest frame, overflow_count=%lu\n", j_txbuf.overflow);
+ }else{
+ j_txbuf.count++;
+ }
+ J1939_CRITICAL_EXIT();
+}
+
+static uint8_t J1939_TxBufferPeek(j1939_tx_frame_t *frame){
+ uint8_t ok = 0;
+ J1939_CRITICAL_ENTER();
+ if(j_txbuf.count > 0){
+ *frame = j_txbuf.buffer[j_txbuf.tail];
+ ok = 1;
+ }
+ J1939_CRITICAL_EXIT();
+ return ok;
+}
+
+static void J1939_TxBufferDropFirst(void){
+ J1939_CRITICAL_ENTER();
+ if(j_txbuf.count > 0){
+ j_txbuf.tail = (j_txbuf.tail + 1U) % J1939_BUFFER_SIZE;
+ j_txbuf.count--;
+ }
+ J1939_CRITICAL_EXIT();
+}
+
+static void J1939_TxQueueByPgn(uint32_t PGN, uint8_t pri, uint8_t DLC, const uint8_t *data, uint8_t pad_ff){
+ j1939_tx_frame_t frame;
+ uint8_t i;
+
+ frame.ExtId = (pri << 26) | (PGN << 8) | (J_ID_SE << 8) | J_ID_EV;
+ frame.DLC = DLC;
+ for(i = 0; i < 8; i++){
+ if(i < DLC) frame.data[i] = data[i];
+ else frame.data[i] = pad_ff ? 0xFF : 0x00;
+ }
+ J1939_TxBufferAdd(&frame);
+}
diff --git a/Core/Src/load.c b/Core/Src/load.c
new file mode 100644
index 0000000..578f242
--- /dev/null
+++ b/Core/Src/load.c
@@ -0,0 +1,45 @@
+#include "load.h"
+#include "board.h"
+#include "debug.h"
+#include "connector.h"
+
+#define COOLDOWN_TIME 60000
+
+void LOAD_Init(){
+ RELAY_Write(RELAY_1, 0);
+ RELAY_Write(RELAY_2, 0);
+ RELAY_Write(RELAY_3, 0);
+ RELAY_Write(RELAY_4, 0);
+ RELAY_Write(RELAY_5, 0);
+}
+
+void LOAD_Task(){
+ static uint32_t load_tick = 0;
+ if(CONN[0].enableLoad || CONN[1].enableLoad){
+ load_tick = HAL_GetTick();
+ }
+
+ if((HAL_GetTick() - load_tick < COOLDOWN_TIME) && (load_tick!=0)){
+ RELAY_Write(RELAY_1, 1);
+ }else{
+ RELAY_Write(RELAY_1, 0);
+ }
+
+
+ if(CONN[0].enableLoad){
+ RELAY_Write(RELAY_2, 1);
+ }else{
+ RELAY_Write(RELAY_2, 0);
+ }
+ if(CONN[1].enableLoad){
+ RELAY_Write(RELAY_3, 1);
+ }else{
+ RELAY_Write(RELAY_3, 0);
+ }
+
+ // if(CONN[0].enableLoad && CONN[1].enableLoad){ // объединение нагрузок
+ // RELAY_Write(RELAY_4, 0);
+ // }else{
+ // RELAY_Write(RELAY_4, 1);
+ // }
+}
\ No newline at end of file
diff --git a/Core/Src/main.c b/Core/Src/main.c
index 838ba1d..d0deecf 100644
--- a/Core/Src/main.c
+++ b/Core/Src/main.c
@@ -30,13 +30,15 @@
#include "can.h"
#include "board.h"
#include
-#include "debug.h"
#include "charger_gbt.h"
#include "soft_rtc.h"
#include "j1939.h"
#include "connector.h"
#include "rgb_controller.h"
-
+#include "serial_control.h"
+#include "cp.h"
+#include "debug.h"
+#include "load.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
@@ -60,6 +62,7 @@
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
+volatile CP_State_t cp_state = EV_STATE_B_CONN_PREP;
/* USER CODE END PV */
@@ -116,23 +119,26 @@ int main(void)
MX_UART5_Init();
MX_USART1_UART_Init();
MX_USART3_UART_Init();
+ MX_TIM3_Init();
/* USER CODE BEGIN 2 */
CAN_ReInit();
Init_Peripheral();
LED_Init();
-
+ LOAD_Init();
HAL_Delay(300);
GBT_Init();
set_Time(1721651966);
- printf("Startup (type \'help\' for command list)\n");
- debug_init();
- EDCAN_Init(0x00);
- EDCAN_printf(LOG_INFO, "Startup FW %d.%d.%d\n", FWVER_MAJOR, FWVER_MINOR, FWVER_PATCH);
+ // printf("Startup serial control enabled\n");
+ EDCAN_Init(InfoBlock->addrEdcan);
+ log_printf(LOG_INFO, "Startup FW %d.%d.%d\n", FWVER_MAJOR, FWVER_MINOR, FWVER_PATCH);
//EDCAN_Init(0x20); //Адрес EDCAN
GBT_CAN_ReInit();
CAN_ReInit();
CONN_Init();
+ SC_Init();
+ CP_Init();
+
/* USER CODE END 2 */
/* Infinite loop */
@@ -142,10 +148,15 @@ int main(void)
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
-// HAL_Delay(1);
+
+ CONN[1].MeasuredVoltage = ISO.voltageComm;
+ LOAD_Task();
EDCAN_Loop();
//can_task();
- debug_task();
+ J1939_ExchangeRxBuffer();
+ J1939_ExchangeTxBuffer();
+ SC_Task();
+ CP_Task();
CONN_CC_ReadStateFiltered();
// GBT_ManageLock();
CONN_Task();
diff --git a/Core/Src/rgb_controller.c b/Core/Src/rgb_controller.c
index b5f211b..d1a52ba 100644
--- a/Core/Src/rgb_controller.c
+++ b/Core/Src/rgb_controller.c
@@ -90,11 +90,11 @@ RGB_Cycle_t color_error = {
};
void LED_Write(){
- if(CONN.chargingError != CONN_NO_ERROR){
+ if(CONN[0].chargingError != CONN_NO_ERROR){
LED_SetColor(&color_error);
return;
}
- switch(CONN.connState){
+ switch(CONN[0].connState){
case Unknown:
LED_SetColor(&color_unknown);
break;
diff --git a/Core/Src/serial_control.c b/Core/Src/serial_control.c
new file mode 100644
index 0000000..251472e
--- /dev/null
+++ b/Core/Src/serial_control.c
@@ -0,0 +1,191 @@
+#include "serial_control.h"
+#include "usart.h"
+#include "charger_gbt.h"
+#include "edcan_config.h"
+#include "string.h"
+
+static uint32_t calculate_crc32(const uint8_t *data, uint16_t length);
+static uint16_t encode_packet(const uint8_t *payload, uint16_t payload_len, uint8_t *output, uint8_t response_code);
+static uint8_t parse_packet(const uint8_t *packet_data, uint16_t packet_len, ReceivedCommand_t *out_cmd);
+static uint8_t process_received_packet(SerialControl_t *ctx, const uint8_t *packet_data, uint16_t packet_len);
+static void SC_ArmUart2Rx(void);
+
+SerialControl_t serial_control;
+static SerialControl_t serial_iso;
+volatile SC_Source_t g_sc_command_source = SC_SOURCE_UART2;
+
+GBT_MonitorPacket_t gbtMonitorPacket = {
+ .connector_type = 0x01,
+};
+
+CCS_MonitorPacket_t ccsMonitorPacket = {
+ .connector_type = 0x02,
+};
+
+InfoPacket_t infoPacket = {
+ .serialNumber = 0,
+ .boardVersion = 0,
+ .stationType = 0,
+ .fw_version_major = 0,
+ .fw_version_minor = 0,
+ .fw_version_patch = 0,
+};
+
+void SC_Init(void) {
+ memset(&serial_control, 0, sizeof(serial_control));
+ memset(&serial_iso, 0, sizeof(serial_iso));
+}
+
+void SC_Task(void) {
+ SC_ArmUart2Rx();
+ if ((&huart5)->RxState == HAL_UART_STATE_READY) {
+ (void)HAL_UARTEx_ReceiveToIdle_IT(&huart5, serial_iso.rx_buffer, MAX_RX_BUFFER_SIZE - 1);
+ }
+
+ if (huart2.gState == HAL_UART_STATE_BUSY_TX && serial_control.tx_tick != 0U) {
+ if ((HAL_GetTick() - serial_control.tx_tick) > 100U) {
+ HAL_UART_Abort_IT(&huart2);
+ HAL_GPIO_WritePin(USART2_DIR_GPIO_Port, USART2_DIR_Pin, GPIO_PIN_RESET);
+ serial_control.tx_tick = 0U;
+ }
+ }
+
+ if (serial_control.command_ready && (huart2.gState != HAL_UART_STATE_BUSY_TX)) {
+ SC_CommandHandler((ReceivedCommand_t *)&serial_control.received_command);
+ serial_control.command_ready = 0U;
+ SC_ArmUart2Rx();
+ }
+
+ if (serial_control.response_pending && (huart2.gState != HAL_UART_STATE_BUSY_TX)) {
+ SC_SendPacket(NULL, 0, serial_control.response_code);
+ serial_control.response_pending = 0U;
+ }
+}
+
+void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) {
+ if (huart->Instance == huart2.Instance) {
+ if (!process_received_packet(&serial_control, serial_control.rx_buffer, Size)) {
+ serial_control.response_pending = 1U;
+ serial_control.response_code = RESP_INVALID;
+ SC_ArmUart2Rx();
+ } else {
+ g_sc_command_source = SC_SOURCE_UART2;
+ }
+ } else if (huart->Instance == huart5.Instance) {
+ if (process_received_packet(&serial_iso, serial_iso.rx_buffer, Size)) {
+ g_sc_command_source = SC_SOURCE_UART5;
+ SC_CommandHandler((ReceivedCommand_t *)&serial_iso.received_command);
+ }
+ (void)HAL_UARTEx_ReceiveToIdle_IT(&huart5, serial_iso.rx_buffer, MAX_RX_BUFFER_SIZE - 1);
+ }
+}
+
+void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) {
+ if (huart->Instance == huart2.Instance) {
+ SC_ArmUart2Rx();
+ }
+}
+
+void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
+ if (huart->Instance == huart2.Instance) {
+ HAL_GPIO_WritePin(USART2_DIR_GPIO_Port, USART2_DIR_Pin, GPIO_PIN_RESET);
+ serial_control.tx_tick = 0U;
+ }
+}
+
+static void SC_ArmUart2Rx(void) {
+ if ((&huart2)->RxState == HAL_UART_STATE_READY && serial_control.command_ready == 0U) {
+ (void)HAL_UARTEx_ReceiveToIdle_IT(&huart2, serial_control.rx_buffer, MAX_RX_BUFFER_SIZE - 1);
+ }
+}
+
+static uint32_t calculate_crc32(const uint8_t *data, uint16_t length) {
+ uint32_t crc = 0xFFFFFFFFu;
+
+ for (uint16_t i = 0; i < length; i++) {
+ crc ^= data[i];
+ for (uint8_t bit = 0; bit < 8; bit++) {
+ if (crc & 0x1u) {
+ crc = (crc >> 1) ^ CRC32_POLYNOMIAL;
+ } else {
+ crc >>= 1;
+ }
+ }
+ }
+
+ return crc ^ 0xFFFFFFFFu;
+}
+
+static uint16_t encode_packet(const uint8_t *payload, uint16_t payload_len, uint8_t *output, uint8_t response_code) {
+ uint16_t out_index = 0;
+
+ output[out_index++] = response_code;
+
+ if (payload != NULL) {
+ for (uint16_t i = 0; i < payload_len; i++) {
+ output[out_index++] = payload[i];
+ if (out_index >= MAX_TX_BUFFER_SIZE - 5) {
+ return 0;
+ }
+ }
+ }
+
+ uint32_t crc = calculate_crc32(output, out_index);
+ uint8_t *crc_bytes = (uint8_t *)&crc;
+
+ for (uint8_t i = 0; i < 4; i++) {
+ output[out_index++] = crc_bytes[i];
+ if (out_index >= MAX_TX_BUFFER_SIZE - 1) {
+ return 0;
+ }
+ }
+
+ return out_index;
+}
+
+void SC_SendPacket(const uint8_t *payload, uint16_t payload_len, uint8_t response_code) {
+ uint16_t packet_len = encode_packet(payload, payload_len, serial_control.tx_buffer, response_code);
+
+ if (packet_len > 0U) {
+ if (huart2.gState == HAL_UART_STATE_BUSY_TX) {
+ HAL_UART_Abort_IT(&huart2);
+ HAL_GPIO_WritePin(USART2_DIR_GPIO_Port, USART2_DIR_Pin, GPIO_PIN_RESET);
+ }
+
+ HAL_GPIO_WritePin(USART2_DIR_GPIO_Port, USART2_DIR_Pin, GPIO_PIN_SET);
+ HAL_UART_Transmit_IT(&huart2, serial_control.tx_buffer, packet_len);
+ serial_control.tx_tick = HAL_GetTick();
+ }
+}
+
+static uint8_t parse_packet(const uint8_t *packet_data, uint16_t packet_len, ReceivedCommand_t *out_cmd) {
+ if (packet_len < 5U || packet_len > MAX_RX_BUFFER_SIZE) {
+ return 0U;
+ }
+
+ uint16_t payload_length = packet_len - 4U;
+ uint32_t received_checksum =
+ ((uint32_t)packet_data[payload_length] << 0) |
+ ((uint32_t)packet_data[payload_length + 1U] << 8) |
+ ((uint32_t)packet_data[payload_length + 2U] << 16) |
+ ((uint32_t)packet_data[payload_length + 3U] << 24);
+
+ uint32_t calculated_checksum = calculate_crc32(packet_data, payload_length);
+ if (received_checksum != calculated_checksum) {
+ return 0U;
+ }
+
+ out_cmd->command = packet_data[0];
+ out_cmd->argument = (void *)&packet_data[1];
+ out_cmd->argument_length = (uint8_t)(payload_length - 1U);
+ return 1U;
+}
+
+static uint8_t process_received_packet(SerialControl_t *ctx, const uint8_t *packet_data, uint16_t packet_len) {
+ if (!parse_packet(packet_data, packet_len, (ReceivedCommand_t *)&ctx->received_command)) {
+ return 0U;
+ }
+
+ ctx->command_ready = 1U;
+ return 1U;
+}
diff --git a/Core/Src/serial_handler.c b/Core/Src/serial_handler.c
new file mode 100644
index 0000000..bcf1aaa
--- /dev/null
+++ b/Core/Src/serial_handler.c
@@ -0,0 +1,159 @@
+#include "serial_control.h"
+#include "charger_gbt.h"
+#include "cp.h"
+#include "edcan_config.h"
+#include
+#include "board.h"
+#include "debug.h"
+
+static void SC_FillGBTMonitorPacket(void);
+static void SC_FillCCSMonitorPacket(void);
+static void SC_FillInfoPacket(void);
+
+IsolationStatusPacket_t ISO = {
+ .isolationResistance = 0xFFFF
+};
+
+void SC_CommandHandler(ReceivedCommand_t *cmd) {
+ uint8_t response_code = RESP_FAILED;
+
+ if (cmd->command == CMD_ISOLATION_STATUS) {
+ if (cmd->argument_length == sizeof(IsolationStatusPacket_t)) {
+ memcpy(&ISO, cmd->argument, sizeof(IsolationStatusPacket_t));
+ if (g_sc_command_source == SC_SOURCE_UART5) {
+ return;
+ }
+ response_code = RESP_SUCCESS;
+ } else {
+ response_code = RESP_FAILED;
+ }
+ SC_SendPacket(NULL, 0, response_code);
+ return;
+ }
+
+ switch (cmd->command) {
+
+ case CMD_GET_GBT_STATUS:
+ SC_FillGBTMonitorPacket();
+ SC_SendPacket((const uint8_t *)&gbtMonitorPacket, sizeof(gbtMonitorPacket), CMD_GET_GBT_STATUS);
+ return;
+
+ case CMD_GET_CCS_STATUS:
+ SC_FillCCSMonitorPacket();
+ SC_SendPacket((const uint8_t *)&ccsMonitorPacket, sizeof(ccsMonitorPacket), CMD_GET_CCS_STATUS);
+ return;
+
+ case CMD_GET_INFO:
+ SC_FillInfoPacket();
+ SC_SendPacket((const uint8_t *)&infoPacket, sizeof(infoPacket), CMD_GET_INFO);
+ return;
+
+ case CMD_GET_LOG:
+ debug_buffer_send();
+ return;
+
+ case CMD_GBT_CC_ENABLE:
+ if (cmd->argument_length == sizeof(uint8_t)) {
+ uint8_t enable = *((uint8_t *)cmd->argument);
+ cc_enable = enable ? 1U : 0U;
+ response_code = RESP_SUCCESS;
+ }
+ break;
+
+ case CMD_GBT_STOP:
+ if (cmd->argument_length == 0U) {
+ CONN[0].connControl = CMD_STOP;
+ response_code = RESP_SUCCESS;
+ }
+ break;
+
+ case CMD_GBT_SET_REQUEST:
+ if (cmd->argument_length == sizeof(EvSetLimits_t)) {
+ EvSetLimits_t *limits = (EvSetLimits_t *)cmd->argument;
+ CONN[0].RequestedVoltage = limits->requestedVoltage;
+ CONN[0].RequestedCurrent = limits->requestedCurrent;
+ response_code = RESP_SUCCESS;
+ }
+ break;
+
+ case CMD_GBT_SET_SOC:
+ if (cmd->argument_length == sizeof(uint8_t)) {
+ CONN[0].SOC = *((uint8_t *)cmd->argument);
+ response_code = RESP_SUCCESS;
+ }
+ break;
+
+ case CMD_GBT_SET_VIN:
+ if (cmd->argument_length == 17U) {
+ memcpy(GBT_EVInfo.EVIN, cmd->argument, 17U);
+ response_code = RESP_SUCCESS;
+ }
+ break;
+
+ case CMD_CCS_SET_STATE:
+ if (cmd->argument_length == sizeof(uint8_t)) {
+ cp_state = (CP_State_t)(*((uint8_t *)cmd->argument));
+ response_code = RESP_SUCCESS;
+ }
+ break;
+
+ case CMD_CCS_ENABLE_LOAD:
+ if (cmd->argument_length == sizeof(uint8_t)) {
+ uint8_t enable = *((uint8_t *)cmd->argument);
+ CONN[1].enableLoad = enable ? 1U : 0U;
+ CONN[1].ContactorEnabled = CONN[1].enableLoad;
+ response_code = RESP_SUCCESS;
+ }
+ break;
+
+ default:
+ response_code = RESP_FAILED;
+ break;
+ }
+
+ SC_SendPacket(NULL, 0, response_code);
+}
+
+static void SC_FillInfoPacket(void) {
+ infoPacket.serialNumber = 0;
+ infoPacket.boardVersion = 0;
+ infoPacket.stationType = 0;
+ infoPacket.fw_version_major = FWVER_MAJOR;
+ infoPacket.fw_version_minor = FWVER_MINOR;
+ infoPacket.fw_version_patch = FWVER_PATCH;
+}
+
+static void SC_FillGBTMonitorPacket(void) {
+ gbtMonitorPacket.connector_type = 0x01;
+ gbtMonitorPacket.requestedVoltage = CONN[0].RequestedVoltage;
+ gbtMonitorPacket.requestedCurrent = CONN[0].RequestedCurrent;
+ gbtMonitorPacket.measuredVoltageSE = CONN[0].MeasuredVoltageSE;
+ gbtMonitorPacket.measuredCurrentSE = CONN[0].MeasuredCurrentSE;
+ gbtMonitorPacket.measuredVoltage = CONN[0].MeasuredVoltage;
+ gbtMonitorPacket.measuredCurrent = CONN[0].MeasuredCurrent;
+ gbtMonitorPacket.cc_enabled = cc_enable;
+ gbtMonitorPacket.contactorEnabled = CONN[0].ContactorEnabled;
+ gbtMonitorPacket.chargingError = CONN[0].chargingError;
+ gbtMonitorPacket.EvseConnected = CONN[0].EvseConnected;
+ gbtMonitorPacket.soc = CONN[0].SOC;
+ memcpy(gbtMonitorPacket.vin, GBT_EVInfo.EVIN, sizeof(gbtMonitorPacket.vin));
+ gbtMonitorPacket.cc_state = CONN_CC_GetState();
+ gbtMonitorPacket.logs_available = (debug_buffer_available() > 0U) ? 1U : 0U;
+ gbtMonitorPacket.connState = CONN[0].connState;
+}
+
+static void SC_FillCCSMonitorPacket(void) {
+ CP_Measurement_t cp_meas = CP_GetMeasurement();
+
+ ccsMonitorPacket.connector_type = 0x02;
+ ccsMonitorPacket.measuredVoltage = CONN[1].MeasuredVoltage;
+ ccsMonitorPacket.measuredCurrent = CONN[1].MeasuredCurrent;
+ ccsMonitorPacket.cp_enabled = (cp_state != EV_STATE_A_IDLE) ? 1U : 0U;
+ ccsMonitorPacket.contactorEnabled = CONN[1].ContactorEnabled;
+ ccsMonitorPacket.chargingError = CONN[1].chargingError;
+ ccsMonitorPacket.EvseConnected = CONN[1].EvseConnected;
+ ccsMonitorPacket.soc = CONN[1].SOC;
+ ccsMonitorPacket.cp_state = (uint8_t)cp_state;
+ ccsMonitorPacket.cp_pwm_duty = cp_meas.valid ? cp_meas.duty_percent : 0U;
+}
+
diff --git a/Core/Src/stm32f1xx_it.c b/Core/Src/stm32f1xx_it.c
old mode 100755
new mode 100644
index 16853bf..e573c79
--- a/Core/Src/stm32f1xx_it.c
+++ b/Core/Src/stm32f1xx_it.c
@@ -57,6 +57,8 @@
/* External variables --------------------------------------------------------*/
extern CAN_HandleTypeDef hcan1;
extern CAN_HandleTypeDef hcan2;
+extern TIM_HandleTypeDef htim3;
+extern UART_HandleTypeDef huart5;
extern UART_HandleTypeDef huart2;
/* USER CODE BEGIN EV */
@@ -214,6 +216,20 @@ void CAN1_RX0_IRQHandler(void)
/* USER CODE END CAN1_RX0_IRQn 1 */
}
+/**
+ * @brief This function handles TIM3 global interrupt.
+ */
+void TIM3_IRQHandler(void)
+{
+ /* USER CODE BEGIN TIM3_IRQn 0 */
+
+ /* USER CODE END TIM3_IRQn 0 */
+ HAL_TIM_IRQHandler(&htim3);
+ /* USER CODE BEGIN TIM3_IRQn 1 */
+
+ /* USER CODE END TIM3_IRQn 1 */
+}
+
/**
* @brief This function handles USART2 global interrupt.
*/
@@ -228,6 +244,20 @@ void USART2_IRQHandler(void)
/* USER CODE END USART2_IRQn 1 */
}
+/**
+ * @brief This function handles UART5 global interrupt.
+ */
+void UART5_IRQHandler(void)
+{
+ /* USER CODE BEGIN UART5_IRQn 0 */
+
+ /* USER CODE END UART5_IRQn 0 */
+ HAL_UART_IRQHandler(&huart5);
+ /* USER CODE BEGIN UART5_IRQn 1 */
+
+ /* USER CODE END UART5_IRQn 1 */
+}
+
/**
* @brief This function handles CAN2 TX interrupt.
*/
diff --git a/Core/Src/tim.c b/Core/Src/tim.c
index 4961217..36a0a9b 100644
--- a/Core/Src/tim.c
+++ b/Core/Src/tim.c
@@ -24,8 +24,62 @@
/* USER CODE END 0 */
+TIM_HandleTypeDef htim3;
TIM_HandleTypeDef htim4;
+/* TIM3 init function */
+void MX_TIM3_Init(void)
+{
+
+ /* USER CODE BEGIN TIM3_Init 0 */
+
+ /* USER CODE END TIM3_Init 0 */
+
+ TIM_ClockConfigTypeDef sClockSourceConfig = {0};
+ TIM_MasterConfigTypeDef sMasterConfig = {0};
+ TIM_IC_InitTypeDef sConfigIC = {0};
+
+ /* USER CODE BEGIN TIM3_Init 1 */
+
+ /* USER CODE END TIM3_Init 1 */
+ htim3.Instance = TIM3;
+ htim3.Init.Prescaler = 0;
+ htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
+ htim3.Init.Period = 65535;
+ htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
+ htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
+ if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
+ {
+ Error_Handler();
+ }
+ sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
+ if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
+ {
+ Error_Handler();
+ }
+ if (HAL_TIM_IC_Init(&htim3) != HAL_OK)
+ {
+ Error_Handler();
+ }
+ sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
+ sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
+ if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
+ {
+ Error_Handler();
+ }
+ sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
+ sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
+ sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
+ sConfigIC.ICFilter = 4;
+ if (HAL_TIM_IC_ConfigChannel(&htim3, &sConfigIC, TIM_CHANNEL_2) != HAL_OK)
+ {
+ Error_Handler();
+ }
+ /* USER CODE BEGIN TIM3_Init 2 */
+
+ /* USER CODE END TIM3_Init 2 */
+
+}
/* TIM4 init function */
void MX_TIM4_Init(void)
{
@@ -92,7 +146,32 @@ void MX_TIM4_Init(void)
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{
- if(tim_baseHandle->Instance==TIM4)
+ GPIO_InitTypeDef GPIO_InitStruct = {0};
+ if(tim_baseHandle->Instance==TIM3)
+ {
+ /* USER CODE BEGIN TIM3_MspInit 0 */
+
+ /* USER CODE END TIM3_MspInit 0 */
+ /* TIM3 clock enable */
+ __HAL_RCC_TIM3_CLK_ENABLE();
+
+ __HAL_RCC_GPIOA_CLK_ENABLE();
+ /**TIM3 GPIO Configuration
+ PA7 ------> TIM3_CH2
+ */
+ GPIO_InitStruct.Pin = CP_PWM_Pin;
+ GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
+ GPIO_InitStruct.Pull = GPIO_NOPULL;
+ HAL_GPIO_Init(CP_PWM_GPIO_Port, &GPIO_InitStruct);
+
+ /* TIM3 interrupt Init */
+ HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0);
+ HAL_NVIC_EnableIRQ(TIM3_IRQn);
+ /* USER CODE BEGIN TIM3_MspInit 1 */
+
+ /* USER CODE END TIM3_MspInit 1 */
+ }
+ else if(tim_baseHandle->Instance==TIM4)
{
/* USER CODE BEGIN TIM4_MspInit 0 */
@@ -137,7 +216,26 @@ void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
{
- if(tim_baseHandle->Instance==TIM4)
+ if(tim_baseHandle->Instance==TIM3)
+ {
+ /* USER CODE BEGIN TIM3_MspDeInit 0 */
+
+ /* USER CODE END TIM3_MspDeInit 0 */
+ /* Peripheral clock disable */
+ __HAL_RCC_TIM3_CLK_DISABLE();
+
+ /**TIM3 GPIO Configuration
+ PA7 ------> TIM3_CH2
+ */
+ HAL_GPIO_DeInit(CP_PWM_GPIO_Port, CP_PWM_Pin);
+
+ /* TIM3 interrupt Deinit */
+ HAL_NVIC_DisableIRQ(TIM3_IRQn);
+ /* USER CODE BEGIN TIM3_MspDeInit 1 */
+
+ /* USER CODE END TIM3_MspDeInit 1 */
+ }
+ else if(tim_baseHandle->Instance==TIM4)
{
/* USER CODE BEGIN TIM4_MspDeInit 0 */
diff --git a/Core/Src/usart.c b/Core/Src/usart.c
index ab44ba1..bef1ff3 100644
--- a/Core/Src/usart.c
+++ b/Core/Src/usart.c
@@ -41,7 +41,7 @@ void MX_UART5_Init(void)
/* USER CODE END UART5_Init 1 */
huart5.Instance = UART5;
- huart5.Init.BaudRate = 115200;
+ huart5.Init.BaudRate = 9600;
huart5.Init.WordLength = UART_WORDLENGTH_8B;
huart5.Init.StopBits = UART_STOPBITS_1;
huart5.Init.Parity = UART_PARITY_NONE;
@@ -70,7 +70,7 @@ void MX_USART1_UART_Init(void)
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
- huart1.Init.BaudRate = 115200;
+ huart1.Init.BaudRate = 460800;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
@@ -173,6 +173,9 @@ void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
+ /* UART5 interrupt Init */
+ HAL_NVIC_SetPriority(UART5_IRQn, 0, 0);
+ HAL_NVIC_EnableIRQ(UART5_IRQn);
/* USER CODE BEGIN UART5_MspInit 1 */
/* USER CODE END UART5_MspInit 1 */
@@ -286,6 +289,8 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
HAL_GPIO_DeInit(GPIOD, GPIO_PIN_2);
+ /* UART5 interrupt Deinit */
+ HAL_NVIC_DisableIRQ(UART5_IRQn);
/* USER CODE BEGIN UART5_MspDeInit 1 */
/* USER CODE END UART5_MspDeInit 1 */
diff --git a/Debug/Core/Src/adc.cyclo b/Debug/Core/Src/adc.cyclo
index 52957bf..81e4a6e 100644
--- a/Debug/Core/Src/adc.cyclo
+++ b/Debug/Core/Src/adc.cyclo
@@ -1,3 +1,3 @@
../Core/Src/adc.c:30:6:MX_ADC1_Init 3
../Core/Src/adc.c:72:6:HAL_ADC_MspInit 2
-../Core/Src/adc.c:106:6:HAL_ADC_MspDeInit 2
+../Core/Src/adc.c:107:6:HAL_ADC_MspDeInit 2
diff --git a/Debug/Core/Src/board.cyclo b/Debug/Core/Src/board.cyclo
index 2d6d166..5fc9591 100644
--- a/Debug/Core/Src/board.cyclo
+++ b/Debug/Core/Src/board.cyclo
@@ -1,8 +1,8 @@
-../Core/Src/board.c:16:6:RELAY_Write 7
-../Core/Src/board.c:26:9:IN_ReadInput 9
-../Core/Src/board.c:58:9:GetBoardTemp 1
-../Core/Src/board.c:70:6:Init_Peripheral 1
-../Core/Src/board.c:81:7:pt1000_to_temperature 1
-../Core/Src/board.c:97:7:calculate_NTC_resistance 2
-../Core/Src/board.c:112:9:GBT_ReadTemp 3
-../Core/Src/board.c:147:6:ADC_Select_Channel 2
+../Core/Src/board.c:16:6:RELAY_Write 8
+../Core/Src/board.c:27:9:IN_ReadInput 9
+../Core/Src/board.c:59:9:GetBoardTemp 1
+../Core/Src/board.c:71:6:Init_Peripheral 1
+../Core/Src/board.c:83:7:pt1000_to_temperature 1
+../Core/Src/board.c:99:7:calculate_NTC_resistance 2
+../Core/Src/board.c:114:9:GBT_ReadTemp 3
+../Core/Src/board.c:149:6:ADC_Select_Channel 2
diff --git a/Debug/Core/Src/charger_gbt.cyclo b/Debug/Core/Src/charger_gbt.cyclo
index b9e2909..142cd70 100644
--- a/Debug/Core/Src/charger_gbt.cyclo
+++ b/Debug/Core/Src/charger_gbt.cyclo
@@ -1,11 +1,11 @@
-../Core/Src/charger_gbt.c:60:6:GBT_Init 1
-../Core/Src/charger_gbt.c:67:6:GBT_ChargerTask 53
-../Core/Src/charger_gbt.c:310:6:GBT_SwitchState 13
-../Core/Src/charger_gbt.c:330:10:GBT_StateTick 1
-../Core/Src/charger_gbt.c:334:6:GBT_Delay 1
-../Core/Src/charger_gbt.c:339:6:GBT_StopEV 3
-../Core/Src/charger_gbt.c:349:6:GBT_StopEVSE 2
-../Core/Src/charger_gbt.c:355:6:GBT_StopOCPP 2
-../Core/Src/charger_gbt.c:361:6:GBT_ForceStop 1
-../Core/Src/charger_gbt.c:368:6:GBT_Error 1
-../Core/Src/charger_gbt.c:376:6:GBT_Reset 1
+../Core/Src/charger_gbt.c:68:6:GBT_Init 1
+../Core/Src/charger_gbt.c:78:6:GBT_ChargerTask 61
+../Core/Src/charger_gbt.c:364:6:GBT_SwitchState 13
+../Core/Src/charger_gbt.c:384:10:GBT_StateTick 1
+../Core/Src/charger_gbt.c:388:6:GBT_Delay 1
+../Core/Src/charger_gbt.c:393:6:GBT_StopEV 3
+../Core/Src/charger_gbt.c:403:6:GBT_StopEVSE 2
+../Core/Src/charger_gbt.c:409:6:GBT_StopOCPP 2
+../Core/Src/charger_gbt.c:415:6:GBT_ForceStop 1
+../Core/Src/charger_gbt.c:422:6:GBT_Error 1
+../Core/Src/charger_gbt.c:430:6:GBT_Reset 1
diff --git a/Debug/Core/Src/connector.cyclo b/Debug/Core/Src/connector.cyclo
index acdcf9b..3aa85ef 100644
--- a/Debug/Core/Src/connector.cyclo
+++ b/Debug/Core/Src/connector.cyclo
@@ -1,7 +1,7 @@
-../Core/Src/connector.c:21:6:CONN_Init 1
-../Core/Src/connector.c:27:6:CONN_Task 18
-../Core/Src/connector.c:112:6:CONN_SetState 15
-../Core/Src/connector.c:134:6:CONN_CC_ReadStateFiltered 4
-../Core/Src/connector.c:153:9:CONN_CC_GetState 1
-../Core/Src/connector.c:156:9:CONN_CC_GetStateRaw 9
-../Core/Src/connector.c:183:7:CONN_CC_GetAdc 1
+../Core/Src/connector.c:23:6:CONN_Init 1
+../Core/Src/connector.c:29:6:CONN_Task 18
+../Core/Src/connector.c:122:6:CONN_SetState 15
+../Core/Src/connector.c:144:6:CONN_CC_ReadStateFiltered 4
+../Core/Src/connector.c:163:9:CONN_CC_GetState 1
+../Core/Src/connector.c:166:9:CONN_CC_GetStateRaw 9
+../Core/Src/connector.c:193:7:CONN_CC_GetAdc 1
diff --git a/Debug/Core/Src/debug.cyclo b/Debug/Core/Src/debug.cyclo
index 12f5e43..4bd93ed 100644
--- a/Debug/Core/Src/debug.cyclo
+++ b/Debug/Core/Src/debug.cyclo
@@ -1,7 +1,6 @@
-../Drivers/CMSIS/Include/core_cm3.h:1762:34:__NVIC_SystemReset 1
-../Core/Src/debug.c:26:5:_write 1
-../Core/Src/debug.c:35:6:HAL_UARTEx_RxEventCallback 2
-../Core/Src/debug.c:45:6:debug_rx_interrupt 1
-../Core/Src/debug.c:51:6:debug_init 1
-../Core/Src/debug.c:61:6:parse_command 25
-../Core/Src/debug.c:220:6:debug_task 2
+../Core/Src/debug.c:34:13:debug_uart1_write 5
+../Core/Src/debug.c:50:5:_write 1
+../Core/Src/debug.c:58:6:debug_buffer_add 3
+../Core/Src/debug.c:74:10:debug_buffer_available 1
+../Core/Src/debug.c:82:6:debug_buffer_send 5
+../Core/Src/debug.c:111:5:log_printf 16
diff --git a/Debug/Core/Src/gbt_packet.cyclo b/Debug/Core/Src/gbt_packet.cyclo
index 789bbc4..adc87be 100644
--- a/Debug/Core/Src/gbt_packet.cyclo
+++ b/Debug/Core/Src/gbt_packet.cyclo
@@ -5,4 +5,5 @@
../Core/Src/gbt_packet.c:39:6:GBT_SendBCL 1
../Core/Src/gbt_packet.c:44:6:GBT_SendBCS 1
../Core/Src/gbt_packet.c:49:6:GBT_SendBSM 1
-../Core/Src/gbt_packet.c:54:6:GBT_SendBSD 1
+../Core/Src/gbt_packet.c:54:6:GBT_SendBST 1
+../Core/Src/gbt_packet.c:59:6:GBT_SendBSD 1
diff --git a/Debug/Core/Src/j1939.cyclo b/Debug/Core/Src/j1939.cyclo
index 65cbe3a..ad130d3 100644
--- a/Debug/Core/Src/j1939.cyclo
+++ b/Debug/Core/Src/j1939.cyclo
@@ -1,6 +1,24 @@
-../Core/Src/j1939.c:20:6:HAL_CAN_RxFifo0MsgPendingCallback 20
-../Core/Src/j1939.c:117:6:GBT_CAN_ReInit 1
-../Core/Src/j1939.c:125:6:J_SendPacket 1
-../Core/Src/j1939.c:146:6:J_SendCTS 2
-../Core/Src/j1939.c:164:6:J_SendACK 1
-../Core/Src/j1939.c:179:6:GBT_CAN_FilterInit 2
+../Core/Src/j1939.c:76:13:J_TxReset 2
+../Core/Src/j1939.c:84:6:J1939_InitBuffers 1
+../Core/Src/j1939.c:91:10:J1939_GetRxBufferCount 1
+../Core/Src/j1939.c:99:10:J1939_GetTxBufferCount 1
+../Core/Src/j1939.c:107:10:J1939_GetRxOverflowCount 1
+../Core/Src/j1939.c:111:10:J1939_GetTxOverflowCount 1
+../Core/Src/j1939.c:115:6:HAL_CAN_RxFifo0MsgPendingCallback 2
+../Core/Src/j1939.c:129:13:J1939_ProcessRxFrame 29
+../Core/Src/j1939.c:231:6:J1939_ExchangeRxBuffer 2
+../Core/Src/j1939.c:239:6:J1939_ExchangeTxBuffer 9
+../Core/Src/j1939.c:282:6:GBT_CAN_ReInit 1
+../Core/Src/j1939.c:291:6:J_SendPacket 3
+../Core/Src/j1939.c:322:13:J_TxCheckTimeout 7
+../Core/Src/j1939.c:343:13:J_SendTpRts 1
+../Core/Src/j1939.c:358:13:J_SendTpDtRange 11
+../Core/Src/j1939.c:406:6:J_SendCTS 2
+../Core/Src/j1939.c:424:6:J_SendACK 1
+../Core/Src/j1939.c:439:6:GBT_CAN_FilterInit 2
+../Core/Src/j1939.c:459:13:J1939_RxBufferAdd 2
+../Core/Src/j1939.c:473:16:J1939_RxBufferGet 2
+../Core/Src/j1939.c:486:13:J1939_TxBufferAdd 2
+../Core/Src/j1939.c:500:16:J1939_TxBufferPeek 2
+../Core/Src/j1939.c:511:13:J1939_TxBufferDropFirst 2
+../Core/Src/j1939.c:520:13:J1939_TxQueueByPgn 4
diff --git a/Debug/Core/Src/main.cyclo b/Debug/Core/Src/main.cyclo
index e46ac26..44aad39 100644
--- a/Debug/Core/Src/main.cyclo
+++ b/Debug/Core/Src/main.cyclo
@@ -1,22 +1,23 @@
../Drivers/CMSIS/Include/core_cm3.h:1762:34:__NVIC_SystemReset 1
-/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:41:16:EDCAN_VectorTableIsPlausible 3
-/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:49:6:EDCAN_VectorBaseConfigF0 1
-/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:84:6:EDCAN_VectorBaseConfigF1 1
-/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:171:6:HAL_CAN_RxFifo1MsgPendingCallback 8
-/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:198:6:HAL_CAN_TxMailbox0CompleteCallback 2
-/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:204:6:HAL_CAN_TxMailbox1CompleteCallback 2
-/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:210:6:HAL_CAN_TxMailbox2CompleteCallback 2
-/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:221:6:EDCAN_Init 1
-/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:240:9:EDCAN_GetBoardVersion 1
-/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:250:6:EDCAN_SetSecondID 1
-/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:260:6:CAN_ReInit 1
-/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:300:6:EDCAN_FilterInit 5
-/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:390:6:EDCAN_SendPacketWrite 1
-/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:427:6:EDCAN_SendPacketWriteLong 2
-/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:451:6:EDCAN_SendPacketRead 1
-/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:487:6:EDCAN_SendPacketReadRequest 1
-/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:519:6:EDCAN_Loop 5
-/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:540:6:EDCAN_SendAlivePacket 1
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:32:13:EDCAN_SelectInfoBlockAddress 2
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:54:16:EDCAN_VectorTableIsPlausible 3
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:62:6:EDCAN_VectorBaseConfigF0 1
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:97:6:EDCAN_VectorBaseConfigF1 1
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:184:6:HAL_CAN_RxFifo1MsgPendingCallback 8
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:211:6:HAL_CAN_TxMailbox0CompleteCallback 2
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:217:6:HAL_CAN_TxMailbox1CompleteCallback 2
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:223:6:HAL_CAN_TxMailbox2CompleteCallback 2
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:234:6:EDCAN_Init 1
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:254:9:EDCAN_GetBoardVersion 1
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:265:6:EDCAN_SetSecondID 1
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:275:6:CAN_ReInit 1
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:315:6:EDCAN_FilterInit 5
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:405:6:EDCAN_SendPacketWrite 1
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:442:6:EDCAN_SendPacketWriteLong 2
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:466:6:EDCAN_SendPacketRead 1
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:502:6:EDCAN_SendPacketReadRequest 1
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:534:6:EDCAN_Loop 5
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan.c:555:6:EDCAN_SendAlivePacket 1
/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan_buffer.c:41:6:EDCAN_TxBufferAdd 2
/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan_buffer.c:57:10:EDCAN_getTxBufferElementCount 1
/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan_buffer.c:65:6:EDCAN_TxBufferPeekFirst 2
@@ -26,15 +27,17 @@
/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan_buffer.c:150:6:EDCAN_RxBufferGet 2
/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan_buffer.c:168:10:EDCAN_getRxBufferElementCount 1
/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan_buffer.c:176:6:EDCAN_ExchangeRxBuffer 5
-/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan_handler.c:40:6:EDCAN_WriteHandler 3
-/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan_handler.c:51:6:EDCAN_EnterBootloader 0
-/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan_handler.c:56:6:EDCAN_WriteSystemRegister 9
-/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan_handler.c:86:9:EDCAN_GetSystemRegisterValue 3
-/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan_handler.c:106:9:EDCAN_GetOwnRegisterValue 2
-/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan_handler.c:125:6:EDCAN_ReadRequestHandler 5
-/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan_log.c:10:6:EDCAN_printf 1
-/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan_log.c:31:6:EDCAN_Log 2
-/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan_log.c:56:6:EDCAN_SendPacketLog 1
-../Core/Src/main.c:81:5:main 1
-../Core/Src/main.c:169:6:SystemClock_Config 4
-../Core/Src/main.c:229:6:Error_Handler 1
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan_handler.c:41:6:EDCAN_WriteHandler 3
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan_handler.c:52:6:EDCAN_EnterBootloader 0
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan_handler.c:57:6:EDCAN_WriteSystemRegister 11
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan_handler.c:91:9:EDCAN_GetSystemRegisterValue 5
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan_handler.c:114:9:EDCAN_GetOwnRegisterValue 2
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan_handler.c:133:6:EDCAN_ReadRequestHandler 5
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan_log.c:11:6:EDCAN_SetLogLevel 2
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan_log.c:18:18:EDCAN_GetLogLevel 2
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan_log.c:26:6:EDCAN_printf 2
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan_log.c:51:6:EDCAN_Log 2
+/Users/colorbass/STM32CubeIDE/workspace_1.12.0/lib_EDCAN/edcan_log.c:76:6:EDCAN_SendPacketLog 1
+../Core/Src/main.c:84:5:main 1
+../Core/Src/main.c:180:6:SystemClock_Config 4
+../Core/Src/main.c:240:6:Error_Handler 1
diff --git a/Debug/Core/Src/stm32f1xx_it.cyclo b/Debug/Core/Src/stm32f1xx_it.cyclo
index aca5fab..06f3d11 100644
--- a/Debug/Core/Src/stm32f1xx_it.cyclo
+++ b/Debug/Core/Src/stm32f1xx_it.cyclo
@@ -1,13 +1,15 @@
-../Core/Src/stm32f1xx_it.c:71:6:NMI_Handler 1
-../Core/Src/stm32f1xx_it.c:86:6:HardFault_Handler 1
-../Core/Src/stm32f1xx_it.c:101:6:MemManage_Handler 1
-../Core/Src/stm32f1xx_it.c:116:6:BusFault_Handler 1
-../Core/Src/stm32f1xx_it.c:131:6:UsageFault_Handler 1
-../Core/Src/stm32f1xx_it.c:146:6:SVC_Handler 1
-../Core/Src/stm32f1xx_it.c:159:6:DebugMon_Handler 1
-../Core/Src/stm32f1xx_it.c:172:6:PendSV_Handler 1
-../Core/Src/stm32f1xx_it.c:185:6:SysTick_Handler 1
-../Core/Src/stm32f1xx_it.c:206:6:CAN1_RX0_IRQHandler 1
-../Core/Src/stm32f1xx_it.c:220:6:USART2_IRQHandler 1
-../Core/Src/stm32f1xx_it.c:234:6:CAN2_TX_IRQHandler 1
-../Core/Src/stm32f1xx_it.c:248:6:CAN2_RX1_IRQHandler 1
+../Core/Src/stm32f1xx_it.c:73:6:NMI_Handler 1
+../Core/Src/stm32f1xx_it.c:88:6:HardFault_Handler 1
+../Core/Src/stm32f1xx_it.c:103:6:MemManage_Handler 1
+../Core/Src/stm32f1xx_it.c:118:6:BusFault_Handler 1
+../Core/Src/stm32f1xx_it.c:133:6:UsageFault_Handler 1
+../Core/Src/stm32f1xx_it.c:148:6:SVC_Handler 1
+../Core/Src/stm32f1xx_it.c:161:6:DebugMon_Handler 1
+../Core/Src/stm32f1xx_it.c:174:6:PendSV_Handler 1
+../Core/Src/stm32f1xx_it.c:187:6:SysTick_Handler 1
+../Core/Src/stm32f1xx_it.c:208:6:CAN1_RX0_IRQHandler 1
+../Core/Src/stm32f1xx_it.c:222:6:TIM3_IRQHandler 1
+../Core/Src/stm32f1xx_it.c:236:6:USART2_IRQHandler 1
+../Core/Src/stm32f1xx_it.c:250:6:UART5_IRQHandler 1
+../Core/Src/stm32f1xx_it.c:264:6:CAN2_TX_IRQHandler 1
+../Core/Src/stm32f1xx_it.c:278:6:CAN2_RX1_IRQHandler 1
diff --git a/Debug/Core/Src/subdir.mk b/Debug/Core/Src/subdir.mk
index 44cc7bf..8ffc1b1 100644
--- a/Debug/Core/Src/subdir.mk
+++ b/Debug/Core/Src/subdir.mk
@@ -10,14 +10,18 @@ C_SRCS += \
../Core/Src/can.c \
../Core/Src/charger_gbt.c \
../Core/Src/connector.c \
+../Core/Src/cp.c \
../Core/Src/debug.c \
../Core/Src/edcan_handler_user.c \
../Core/Src/gbt_packet.c \
../Core/Src/gpio.c \
../Core/Src/j1939.c \
+../Core/Src/load.c \
../Core/Src/main.c \
../Core/Src/rgb_controller.c \
../Core/Src/rtc.c \
+../Core/Src/serial_control.c \
+../Core/Src/serial_handler.c \
../Core/Src/soft_rtc.c \
../Core/Src/stm32f1xx_hal_msp.c \
../Core/Src/stm32f1xx_it.c \
@@ -33,14 +37,18 @@ C_DEPS += \
./Core/Src/can.d \
./Core/Src/charger_gbt.d \
./Core/Src/connector.d \
+./Core/Src/cp.d \
./Core/Src/debug.d \
./Core/Src/edcan_handler_user.d \
./Core/Src/gbt_packet.d \
./Core/Src/gpio.d \
./Core/Src/j1939.d \
+./Core/Src/load.d \
./Core/Src/main.d \
./Core/Src/rgb_controller.d \
./Core/Src/rtc.d \
+./Core/Src/serial_control.d \
+./Core/Src/serial_handler.d \
./Core/Src/soft_rtc.d \
./Core/Src/stm32f1xx_hal_msp.d \
./Core/Src/stm32f1xx_it.d \
@@ -56,14 +64,18 @@ OBJS += \
./Core/Src/can.o \
./Core/Src/charger_gbt.o \
./Core/Src/connector.o \
+./Core/Src/cp.o \
./Core/Src/debug.o \
./Core/Src/edcan_handler_user.o \
./Core/Src/gbt_packet.o \
./Core/Src/gpio.o \
./Core/Src/j1939.o \
+./Core/Src/load.o \
./Core/Src/main.o \
./Core/Src/rgb_controller.o \
./Core/Src/rtc.o \
+./Core/Src/serial_control.o \
+./Core/Src/serial_handler.o \
./Core/Src/soft_rtc.o \
./Core/Src/stm32f1xx_hal_msp.o \
./Core/Src/stm32f1xx_it.o \
@@ -81,7 +93,7 @@ Core/Src/%.o Core/Src/%.su Core/Src/%.cyclo: ../Core/Src/%.c Core/Src/subdir.mk
clean: clean-Core-2f-Src
clean-Core-2f-Src:
- -$(RM) ./Core/Src/adc.cyclo ./Core/Src/adc.d ./Core/Src/adc.o ./Core/Src/adc.su ./Core/Src/board.cyclo ./Core/Src/board.d ./Core/Src/board.o ./Core/Src/board.su ./Core/Src/can.cyclo ./Core/Src/can.d ./Core/Src/can.o ./Core/Src/can.su ./Core/Src/charger_gbt.cyclo ./Core/Src/charger_gbt.d ./Core/Src/charger_gbt.o ./Core/Src/charger_gbt.su ./Core/Src/connector.cyclo ./Core/Src/connector.d ./Core/Src/connector.o ./Core/Src/connector.su ./Core/Src/debug.cyclo ./Core/Src/debug.d ./Core/Src/debug.o ./Core/Src/debug.su ./Core/Src/edcan_handler_user.cyclo ./Core/Src/edcan_handler_user.d ./Core/Src/edcan_handler_user.o ./Core/Src/edcan_handler_user.su ./Core/Src/gbt_packet.cyclo ./Core/Src/gbt_packet.d ./Core/Src/gbt_packet.o ./Core/Src/gbt_packet.su ./Core/Src/gpio.cyclo ./Core/Src/gpio.d ./Core/Src/gpio.o ./Core/Src/gpio.su ./Core/Src/j1939.cyclo ./Core/Src/j1939.d ./Core/Src/j1939.o ./Core/Src/j1939.su ./Core/Src/main.cyclo ./Core/Src/main.d ./Core/Src/main.o ./Core/Src/main.su ./Core/Src/rgb_controller.cyclo ./Core/Src/rgb_controller.d ./Core/Src/rgb_controller.o ./Core/Src/rgb_controller.su ./Core/Src/rtc.cyclo ./Core/Src/rtc.d ./Core/Src/rtc.o ./Core/Src/rtc.su ./Core/Src/soft_rtc.cyclo ./Core/Src/soft_rtc.d ./Core/Src/soft_rtc.o ./Core/Src/soft_rtc.su ./Core/Src/stm32f1xx_hal_msp.cyclo ./Core/Src/stm32f1xx_hal_msp.d ./Core/Src/stm32f1xx_hal_msp.o ./Core/Src/stm32f1xx_hal_msp.su ./Core/Src/stm32f1xx_it.cyclo ./Core/Src/stm32f1xx_it.d ./Core/Src/stm32f1xx_it.o ./Core/Src/stm32f1xx_it.su ./Core/Src/syscalls.cyclo ./Core/Src/syscalls.d ./Core/Src/syscalls.o ./Core/Src/syscalls.su ./Core/Src/sysmem.cyclo ./Core/Src/sysmem.d ./Core/Src/sysmem.o ./Core/Src/sysmem.su ./Core/Src/system_stm32f1xx.cyclo ./Core/Src/system_stm32f1xx.d ./Core/Src/system_stm32f1xx.o ./Core/Src/system_stm32f1xx.su ./Core/Src/tim.cyclo ./Core/Src/tim.d ./Core/Src/tim.o ./Core/Src/tim.su ./Core/Src/usart.cyclo ./Core/Src/usart.d ./Core/Src/usart.o ./Core/Src/usart.su
+ -$(RM) ./Core/Src/adc.cyclo ./Core/Src/adc.d ./Core/Src/adc.o ./Core/Src/adc.su ./Core/Src/board.cyclo ./Core/Src/board.d ./Core/Src/board.o ./Core/Src/board.su ./Core/Src/can.cyclo ./Core/Src/can.d ./Core/Src/can.o ./Core/Src/can.su ./Core/Src/charger_gbt.cyclo ./Core/Src/charger_gbt.d ./Core/Src/charger_gbt.o ./Core/Src/charger_gbt.su ./Core/Src/connector.cyclo ./Core/Src/connector.d ./Core/Src/connector.o ./Core/Src/connector.su ./Core/Src/cp.cyclo ./Core/Src/cp.d ./Core/Src/cp.o ./Core/Src/cp.su ./Core/Src/debug.cyclo ./Core/Src/debug.d ./Core/Src/debug.o ./Core/Src/debug.su ./Core/Src/edcan_handler_user.cyclo ./Core/Src/edcan_handler_user.d ./Core/Src/edcan_handler_user.o ./Core/Src/edcan_handler_user.su ./Core/Src/gbt_packet.cyclo ./Core/Src/gbt_packet.d ./Core/Src/gbt_packet.o ./Core/Src/gbt_packet.su ./Core/Src/gpio.cyclo ./Core/Src/gpio.d ./Core/Src/gpio.o ./Core/Src/gpio.su ./Core/Src/j1939.cyclo ./Core/Src/j1939.d ./Core/Src/j1939.o ./Core/Src/j1939.su ./Core/Src/load.cyclo ./Core/Src/load.d ./Core/Src/load.o ./Core/Src/load.su ./Core/Src/main.cyclo ./Core/Src/main.d ./Core/Src/main.o ./Core/Src/main.su ./Core/Src/rgb_controller.cyclo ./Core/Src/rgb_controller.d ./Core/Src/rgb_controller.o ./Core/Src/rgb_controller.su ./Core/Src/rtc.cyclo ./Core/Src/rtc.d ./Core/Src/rtc.o ./Core/Src/rtc.su ./Core/Src/serial_control.cyclo ./Core/Src/serial_control.d ./Core/Src/serial_control.o ./Core/Src/serial_control.su ./Core/Src/serial_handler.cyclo ./Core/Src/serial_handler.d ./Core/Src/serial_handler.o ./Core/Src/serial_handler.su ./Core/Src/soft_rtc.cyclo ./Core/Src/soft_rtc.d ./Core/Src/soft_rtc.o ./Core/Src/soft_rtc.su ./Core/Src/stm32f1xx_hal_msp.cyclo ./Core/Src/stm32f1xx_hal_msp.d ./Core/Src/stm32f1xx_hal_msp.o ./Core/Src/stm32f1xx_hal_msp.su ./Core/Src/stm32f1xx_it.cyclo ./Core/Src/stm32f1xx_it.d ./Core/Src/stm32f1xx_it.o ./Core/Src/stm32f1xx_it.su ./Core/Src/syscalls.cyclo ./Core/Src/syscalls.d ./Core/Src/syscalls.o ./Core/Src/syscalls.su ./Core/Src/sysmem.cyclo ./Core/Src/sysmem.d ./Core/Src/sysmem.o ./Core/Src/sysmem.su ./Core/Src/system_stm32f1xx.cyclo ./Core/Src/system_stm32f1xx.d ./Core/Src/system_stm32f1xx.o ./Core/Src/system_stm32f1xx.su ./Core/Src/tim.cyclo ./Core/Src/tim.d ./Core/Src/tim.o ./Core/Src/tim.su ./Core/Src/usart.cyclo ./Core/Src/usart.d ./Core/Src/usart.o ./Core/Src/usart.su
.PHONY: clean-Core-2f-Src
diff --git a/Debug/Core/Src/usart.cyclo b/Debug/Core/Src/usart.cyclo
index 73fb3cd..9b978c4 100644
--- a/Debug/Core/Src/usart.cyclo
+++ b/Debug/Core/Src/usart.cyclo
@@ -3,4 +3,4 @@
../Core/Src/usart.c:91:6:MX_USART2_UART_Init 2
../Core/Src/usart.c:120:6:MX_USART3_UART_Init 2
../Core/Src/usart.c:148:6:HAL_UART_MspInit 5
-../Core/Src/usart.c:270:6:HAL_UART_MspDeInit 5
+../Core/Src/usart.c:273:6:HAL_UART_MspDeInit 5
diff --git a/Debug/objects.list b/Debug/objects.list
index 512aeae..41948c0 100644
--- a/Debug/objects.list
+++ b/Debug/objects.list
@@ -3,14 +3,18 @@
"./Core/Src/can.o"
"./Core/Src/charger_gbt.o"
"./Core/Src/connector.o"
+"./Core/Src/cp.o"
"./Core/Src/debug.o"
"./Core/Src/edcan_handler_user.o"
"./Core/Src/gbt_packet.o"
"./Core/Src/gpio.o"
"./Core/Src/j1939.o"
+"./Core/Src/load.o"
"./Core/Src/main.o"
"./Core/Src/rgb_controller.o"
"./Core/Src/rtc.o"
+"./Core/Src/serial_control.o"
+"./Core/Src/serial_handler.o"
"./Core/Src/soft_rtc.o"
"./Core/Src/stm32f1xx_hal_msp.o"
"./Core/Src/stm32f1xx_it.o"
diff --git a/GBT_J1939_DEBUG_FLOW.md b/GBT_J1939_DEBUG_FLOW.md
new file mode 100644
index 0000000..afdb146
--- /dev/null
+++ b/GBT_J1939_DEBUG_FLOW.md
@@ -0,0 +1,180 @@
+# GB/T + J1939 Debug Flow (CAN ExtId)
+
+Документ для ручного дебага обмена EV <-> EVSE по CAN (J1939 TP + short PGN).
+
+## 1) Базовая структура CAN Extended ID (29-bit)
+
+В проекте используется формула:
+
+- `ExtId = (priority << 26) | (PGN << 8) | (SA << 8) | DA`
+
+Где:
+- `priority` — обычно `6` или `7`
+- `PGN` — Parameter Group Number
+- `SA` — Source Address
+- `DA` — Destination Address
+
+Адреса в ваших прошивках:
+- `EVSE (SE)` = `0x56`
+- `EV` = `0xF4`
+
+Примеры:
+- `0x181056F4` -> short PGN `0x1000` (BCL), `SA=0x56`, `DA=0xF4`
+- `0x1CEC56F4` -> TP.CM от `0x56` к `0xF4`
+- `0x1CECF456` -> TP.CM от `0xF4` к `0x56`
+- `0x1CEB56F4` -> TP.DT от `0x56` к `0xF4`
+
+
+## 2) Какие PGN short, какие TP
+
+Short (<=8 байт, один CAN кадр):
+- `0x0900` BRO
+- `0x0A00` CRO
+- `0x1000` BCL (5 байт)
+- `0x1200` CCS
+- `0x1300` BSM (7 байт)
+- `0x1A00` CST
+
+Через TP (>8 байт):
+- `0x0200` BRM (49 байт)
+- `0x0600` BCP (13 байт)
+- `0x1100` BCS (9 байт)
+
+
+## 3) Нормальная последовательность (высокоуровнево)
+
+1. Handshake/recognition:
+- CHM/CRM/BRM/BCP/CML/BRO/CRO
+
+2. Переход в заряд:
+- EVSE `S8 -> S9`
+- EV начинает слать BCL/BSM/BCS
+- EVSE принимает BCL и переходит `S9 -> S10`
+
+3. Во время зарядки:
+- EV регулярно шлет:
+ - BCL (short)
+ - BSM (short)
+ - BCS (TP, `PGN=0x1100`)
+- EVSE регулярно шлет CCS
+
+
+## 4) Нормальная TP-сессия для BCS (`PGN=0x1100`, size=9, packets=2)
+
+### Шаг 1: RTS (originator -> responder)
+
+ID:
+- от EV к EVSE: `1CEC F4 56` (`0x1CECF456`)
+
+Data (TP.CM_RTS):
+- `byte0 = 0x10` (RTS)
+- `byte1..2 = total_size` (LSB/MSB), для BCS: `0x09 0x00`
+- `byte3 = total_packets`, для BCS: `0x02`
+- `byte4 = max_packets_per_CTS` (часто `0x02`)
+- `byte5..7 = PGN` в little-endian (`00 11 00` для `0x1100`)
+
+### Шаг 2: CTS (responder -> originator)
+
+ID:
+- от EVSE к EV: `1CEC 56 F4` (`0x1CEC56F4`)
+
+Data (TP.CM_CTS):
+- `byte0 = 0x11` (CTS)
+- `byte1 = allowed_packet_count`
+- `byte2 = next_packet_number` (обычно `1` для новой сессии)
+- `byte3..4 = 0xFF`
+- `byte5..7 = PGN` (`00 11 00`)
+
+### Шаг 3: DT (originator -> responder)
+
+ID:
+- `1CEB F4 56` (EV -> EVSE)
+
+Data (TP.DT):
+- `byte0 = seq` (`1`, потом `2`)
+- `byte1..7 = payload chunk`
+
+Для 9 байт:
+- DT#1 несет первые 7 байт
+- DT#2 несет оставшиеся 2 байта + заполнение `0xFF`
+
+### Шаг 4: ACK (responder -> originator)
+
+ID:
+- `1CEC 56 F4` (EVSE -> EV)
+
+Data (TP.CM_EndOfMsgACK):
+- `byte0 = 0x13` (ACK)
+- `byte1..2 = total_size` (`09 00`)
+- `byte3 = total_packets` (`02`)
+- `byte4 = 0xFF`
+- `byte5..7 = PGN` (`00 11 00`)
+
+
+## 5) Как понять по логу, что сессия "правильная"
+
+Для каждого `RTS(0x1100)` должен быть полный шаблон:
+- `RTS` -> `CTS` -> `DT #1` -> `DT #2` -> `ACK`
+
+Если есть `RTS`, но нет `CTS`:
+- проблема на стороне responder (EVSE) TX/фильтр/перегрузка
+
+Если есть `CTS`, но нет `DT`:
+- проблема на стороне originator (EV) RX/парсинг/состояние
+
+Если есть `DT`, но нет `ACK`:
+- проблема на стороне responder reassembly/timeout
+
+
+## 6) Поля основных GB/T пакетов (payload)
+
+### BCL (`PGN 0x1000`, short, 5 bytes)
+Структура:
+- `requestedVoltage` (`uint16`, 0.1V/bit)
+- `requestedCurrent` (`uint16`, 0.1A/bit, в вашем коде может интерпретироваться как `4000 - value`)
+- `chargingMode` (`uint8`, `0x01` CV, `0x02` CC)
+
+### BCS (`PGN 0x1100`, TP, 9 bytes)
+Структура:
+- `measuredChargingVoltage` (`uint16`)
+- `measuredChargingCurrent` (`uint16`)
+- `highestVoltageOfBatteryCell` (`uint16`)
+- `currentChargeState` (`uint8`)
+- `estimatedRemainingChargingTime` (`uint16`)
+
+### BSM (`PGN 0x1300`, short, 7 bytes)
+Структура:
+- max/temperature индексы и статусы:
+ - `singleBatteryHighestVoltageSerNo`
+ - `batteryHighestTemp`
+ - `batteryHighestTempSerNo`
+ - `batteryLowestTemp`
+ - `batteryLowestTempSerNo`
+ - `batteryCellVoltageState`
+ - `batteryStatus`
+
+
+## 7) Тайминги TP из J1939 (важное для дебага)
+
+Ключевые reference значения:
+- `Tr = 200 ms`
+- `Th = 500 ms`
+- `T1 = 750 ms`
+- `T2 = 1250 ms`
+- `T3 = 1250 ms`
+- `T4 = 1050 ms`
+
+Практически:
+- если responder выдал CTS, originator не должен задерживать DT дольше допусков
+- если originator отправил RTS/DT, responder должен ответить CTS/ACK в окне таймаутов
+
+
+## 8) Мини-чеклист при "вдруг стопнулось"
+
+1. Найти последний `RTS` по `PGN=0x1100`.
+2. Проверить, был ли `CTS` на шине с тем же `PGN`.
+3. Проверить наличие `DT#1/#2`.
+4. Проверить `ACK`.
+5. Если цепочка оборвалась:
+ - зафиксировать на каком шаге;
+ - сопоставить с UART логом state machine (`S9/S10`, `TP timeout`, `BCS timeout`).
diff --git a/GbTModuleEV.ioc b/GbTModuleEV.ioc
index c68fe63..d7d166e 100755
--- a/GbTModuleEV.ioc
+++ b/GbTModuleEV.ioc
@@ -37,69 +37,76 @@ Mcu.CPN=STM32F107VCT6
Mcu.Family=STM32F1
Mcu.IP0=ADC1
Mcu.IP1=CAN1
-Mcu.IP10=USART2
-Mcu.IP11=USART3
+Mcu.IP10=USART1
+Mcu.IP11=USART2
+Mcu.IP12=USART3
Mcu.IP2=CAN2
Mcu.IP3=NVIC
Mcu.IP4=RCC
Mcu.IP5=RTC
Mcu.IP6=SYS
-Mcu.IP7=TIM4
-Mcu.IP8=UART5
-Mcu.IP9=USART1
-Mcu.IPNb=12
+Mcu.IP7=TIM3
+Mcu.IP8=TIM4
+Mcu.IP9=UART5
+Mcu.IPNb=13
Mcu.Name=STM32F107V(B-C)Tx
Mcu.Package=LQFP100
Mcu.Pin0=PC14-OSC32_IN
Mcu.Pin1=PC15-OSC32_OUT
-Mcu.Pin10=PB0
-Mcu.Pin11=PB1
-Mcu.Pin12=PE7
-Mcu.Pin13=PE8
-Mcu.Pin14=PE9
-Mcu.Pin15=PE10
-Mcu.Pin16=PE11
-Mcu.Pin17=PE12
-Mcu.Pin18=PE14
-Mcu.Pin19=PD13
+Mcu.Pin10=PA5
+Mcu.Pin11=PA6
+Mcu.Pin12=PA7
+Mcu.Pin13=PC4
+Mcu.Pin14=PC5
+Mcu.Pin15=PB0
+Mcu.Pin16=PB1
+Mcu.Pin17=PE7
+Mcu.Pin18=PE8
+Mcu.Pin19=PE9
Mcu.Pin2=OSC_IN
-Mcu.Pin20=PD14
-Mcu.Pin21=PD15
-Mcu.Pin22=PA9
-Mcu.Pin23=PA10
-Mcu.Pin24=PA13
-Mcu.Pin25=PA14
-Mcu.Pin26=PA15
-Mcu.Pin27=PC10
-Mcu.Pin28=PC11
-Mcu.Pin29=PC12
+Mcu.Pin20=PE10
+Mcu.Pin21=PE11
+Mcu.Pin22=PE12
+Mcu.Pin23=PE14
+Mcu.Pin24=PD13
+Mcu.Pin25=PD14
+Mcu.Pin26=PD15
+Mcu.Pin27=PA9
+Mcu.Pin28=PA10
+Mcu.Pin29=PA13
Mcu.Pin3=OSC_OUT
-Mcu.Pin30=PD0
-Mcu.Pin31=PD1
-Mcu.Pin32=PD2
-Mcu.Pin33=PD3
-Mcu.Pin34=PD4
-Mcu.Pin35=PD5
-Mcu.Pin36=PD6
-Mcu.Pin37=PD7
-Mcu.Pin38=PB3
-Mcu.Pin39=PB4
-Mcu.Pin4=PA1
-Mcu.Pin40=PB5
-Mcu.Pin41=PB6
-Mcu.Pin42=PB7
-Mcu.Pin43=PB8
-Mcu.Pin44=PB9
-Mcu.Pin45=PE1
-Mcu.Pin46=VP_RTC_VS_RTC_Activate
-Mcu.Pin47=VP_SYS_VS_Systick
-Mcu.Pin48=VP_TIM4_VS_ClockSourceINT
-Mcu.Pin5=PA2
-Mcu.Pin6=PA3
-Mcu.Pin7=PA6
-Mcu.Pin8=PC4
-Mcu.Pin9=PC5
-Mcu.PinsNb=49
+Mcu.Pin30=PA14
+Mcu.Pin31=PA15
+Mcu.Pin32=PC10
+Mcu.Pin33=PC11
+Mcu.Pin34=PC12
+Mcu.Pin35=PD0
+Mcu.Pin36=PD1
+Mcu.Pin37=PD2
+Mcu.Pin38=PD3
+Mcu.Pin39=PD4
+Mcu.Pin4=PC2
+Mcu.Pin40=PD5
+Mcu.Pin41=PD6
+Mcu.Pin42=PD7
+Mcu.Pin43=PB3
+Mcu.Pin44=PB4
+Mcu.Pin45=PB5
+Mcu.Pin46=PB6
+Mcu.Pin47=PB7
+Mcu.Pin48=PB8
+Mcu.Pin49=PB9
+Mcu.Pin5=PC3
+Mcu.Pin50=PE1
+Mcu.Pin51=VP_RTC_VS_RTC_Activate
+Mcu.Pin52=VP_SYS_VS_Systick
+Mcu.Pin53=VP_TIM3_VS_ClockSourceINT
+Mcu.Pin54=VP_TIM4_VS_ClockSourceINT
+Mcu.Pin6=PA1
+Mcu.Pin7=PA2
+Mcu.Pin8=PA3
+Mcu.Pin9=PA4
+Mcu.PinsNb=55
Mcu.ThirdPartyNb=0
Mcu.UserConstants=
Mcu.UserName=STM32F107VCTx
@@ -118,6 +125,8 @@ NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:false\:true\:false
+NVIC.TIM3_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
+NVIC.UART5_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
NVIC.USART2_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
OSC_IN.Mode=HSE-External-Oscillator
@@ -147,10 +156,20 @@ PA2.Locked=true
PA2.Signal=GPIO_Input
PA3.Locked=true
PA3.Signal=ADCx_IN3
+PA4.Locked=true
+PA4.Signal=ADCx_IN4
+PA5.GPIOParameters=GPIO_Label
+PA5.GPIO_Label=CP_STATE_C
+PA5.Locked=true
+PA5.Signal=GPIO_Output
PA6.GPIOParameters=GPIO_Label
PA6.GPIO_Label=ADC_CC1
PA6.Locked=true
PA6.Signal=ADCx_IN6
+PA7.GPIOParameters=GPIO_Label
+PA7.GPIO_Label=CP_PWM
+PA7.Locked=true
+PA7.Signal=S_TIM3_CH2
PA9.Locked=true
PA9.Mode=Asynchronous
PA9.Signal=USART1_TX
@@ -196,6 +215,14 @@ PC14-OSC32_IN.Mode=LSE-External-Oscillator
PC14-OSC32_IN.Signal=RCC_OSC32_IN
PC15-OSC32_OUT.Mode=LSE-External-Oscillator
PC15-OSC32_OUT.Signal=RCC_OSC32_OUT
+PC2.GPIOParameters=GPIO_Label
+PC2.GPIO_Label=CP_STATE_F
+PC2.Locked=true
+PC2.Signal=GPIO_Output
+PC3.GPIOParameters=GPIO_Label
+PC3.GPIO_Label=CP_RELAY
+PC3.Locked=true
+PC3.Signal=GPIO_Output
PC4.GPIOParameters=GPIO_Label
PC4.GPIO_Label=LOCK_A
PC4.Locked=true
@@ -246,11 +273,11 @@ PE10.GPIO_Label=RELAY3
PE10.Locked=true
PE10.Signal=GPIO_Output
PE11.GPIOParameters=GPIO_Label
-PE11.GPIO_Label=RELAY2
+PE11.GPIO_Label=RELAY4
PE11.Locked=true
PE11.Signal=GPIO_Output
PE12.GPIOParameters=GPIO_Label
-PE12.GPIO_Label=RELAY1
+PE12.GPIO_Label=RELAY5
PE12.Locked=true
PE12.Signal=GPIO_Output
PE14.GPIOParameters=GPIO_Label
@@ -262,11 +289,11 @@ PE7.GPIO_Label=IN0
PE7.Locked=true
PE7.Signal=GPIO_Input
PE8.GPIOParameters=GPIO_Label
-PE8.GPIO_Label=RELAY5
+PE8.GPIO_Label=RELAY1
PE8.Locked=true
PE8.Signal=GPIO_Output
PE9.GPIOParameters=GPIO_Label
-PE9.GPIO_Label=RELAY4
+PE9.GPIO_Label=RELAY2
PE9.Locked=true
PE9.Signal=GPIO_Output
PinOutPanel.RotationAngle=-90
@@ -285,7 +312,7 @@ ProjectManager.FreePins=false
ProjectManager.HalAssertFull=false
ProjectManager.HeapSize=0x200
ProjectManager.KeepUserCode=true
-ProjectManager.LastFirmware=true
+ProjectManager.LastFirmware=false
ProjectManager.LibraryCopy=1
ProjectManager.MainLocation=Core/Src
ProjectManager.NoMain=false
@@ -301,7 +328,7 @@ ProjectManager.ToolChainLocation=
ProjectManager.UAScriptAfterPath=
ProjectManager.UAScriptBeforePath=
ProjectManager.UnderRoot=true
-ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_ADC1_Init-ADC1-false-HAL-true,4-MX_CAN1_Init-CAN1-false-HAL-true,5-MX_CAN2_Init-CAN2-false-HAL-true,6-MX_RTC_Init-RTC-false-HAL-true,7-MX_TIM4_Init-TIM4-false-HAL-true,8-MX_USART2_UART_Init-USART2-false-HAL-true,9-MX_UART5_Init-UART5-false-HAL-true,10-MX_USART1_UART_Init-USART1-false-HAL-true,11-MX_USART3_UART_Init-USART3-false-HAL-true
+ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_ADC1_Init-ADC1-false-HAL-true,4-MX_CAN1_Init-CAN1-false-HAL-true,5-MX_CAN2_Init-CAN2-false-HAL-true,6-MX_RTC_Init-RTC-false-HAL-true,7-MX_TIM4_Init-TIM4-false-HAL-true,8-MX_USART2_UART_Init-USART2-false-HAL-true,9-MX_UART5_Init-UART5-false-HAL-true,10-MX_USART1_UART_Init-USART1-false-HAL-true,11-MX_USART3_UART_Init-USART3-false-HAL-true,12-MX_TIM3_Init-TIM3-false-HAL-true
RCC.ADCFreqValue=12000000
RCC.ADCPresc=RCC_ADCPCLK2_DIV6
RCC.AHBFreq_Value=72000000
@@ -338,28 +365,37 @@ RCC.USBFreq_Value=48000000
RCC.VCOOutput2Freq_Value=8000000
SH.ADCx_IN3.0=ADC1_IN3,IN3
SH.ADCx_IN3.ConfNb=1
+SH.ADCx_IN4.0=ADC1_IN4,IN4
+SH.ADCx_IN4.ConfNb=1
SH.ADCx_IN6.0=ADC1_IN6
SH.ADCx_IN6.ConfNb=1
SH.ADCx_IN8.0=ADC1_IN8,IN8
SH.ADCx_IN8.ConfNb=1
SH.ADCx_IN9.0=ADC1_IN9,IN9
SH.ADCx_IN9.ConfNb=1
+SH.S_TIM3_CH2.0=TIM3_CH2,Input_Capture2_from_TI2
+SH.S_TIM3_CH2.ConfNb=1
SH.S_TIM4_CH2.0=TIM4_CH2,PWM Generation2 CH2
SH.S_TIM4_CH2.ConfNb=1
SH.S_TIM4_CH3.0=TIM4_CH3,PWM Generation3 CH3
SH.S_TIM4_CH3.ConfNb=1
SH.S_TIM4_CH4.0=TIM4_CH4,PWM Generation4 CH4
SH.S_TIM4_CH4.ConfNb=1
+TIM3.Channel-Input_Capture2_from_TI2=TIM_CHANNEL_2
+TIM3.ICFilter_CH2=4
+TIM3.IPParameters=Channel-Input_Capture2_from_TI2,ICFilter_CH2
TIM4.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2
TIM4.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3
TIM4.Channel-PWM\ Generation4\ CH4=TIM_CHANNEL_4
TIM4.IPParameters=Channel-PWM Generation2 CH2,Channel-PWM Generation3 CH3,Channel-PWM Generation4 CH4,Prescaler,Period
TIM4.Period=100
TIM4.Prescaler=720
-UART5.IPParameters=VirtualMode,Mode
+UART5.BaudRate=9600
+UART5.IPParameters=VirtualMode,Mode,BaudRate
UART5.Mode=MODE_RX
UART5.VirtualMode=Asynchronous
-USART1.IPParameters=VirtualMode
+USART1.BaudRate=460800
+USART1.IPParameters=VirtualMode,BaudRate
USART1.VirtualMode=VM_ASYNC
USART2.IPParameters=VirtualMode
USART2.VirtualMode=VM_ASYNC
@@ -369,6 +405,8 @@ VP_RTC_VS_RTC_Activate.Mode=RTC_Enabled
VP_RTC_VS_RTC_Activate.Signal=RTC_VS_RTC_Activate
VP_SYS_VS_Systick.Mode=SysTick
VP_SYS_VS_Systick.Signal=SYS_VS_Systick
+VP_TIM3_VS_ClockSourceINT.Mode=Internal
+VP_TIM3_VS_ClockSourceINT.Signal=TIM3_VS_ClockSourceINT
VP_TIM4_VS_ClockSourceINT.Mode=Internal
VP_TIM4_VS_ClockSourceINT.Signal=TIM4_VS_ClockSourceINT
board=custom
diff --git a/SERIAL_PROTOCOL.md b/SERIAL_PROTOCOL.md
new file mode 100644
index 0000000..99ee770
--- /dev/null
+++ b/SERIAL_PROTOCOL.md
@@ -0,0 +1,168 @@
+# Serial protocol (GbTModuleEV)
+
+Актуальная версия протокола для `USART2` (binary packet + CRC32).
+
+## 1. Транспорт и формат пакета
+
+- Интерфейс: `USART2`
+- Скорость/параметры UART: задаются в CubeMX (`usart.c`)
+- Направление (RS485 DIR): управляется прошивкой через `USART2_DIR`
+
+Формат **команды от хоста**:
+
+1. `command` (1 byte)
+2. `argument` (`N` bytes, может быть 0)
+3. `crc32` (4 bytes, little-endian) по данным `command + argument`
+
+Формат **ответа от устройства**:
+
+1. `response_code` (1 byte) — обычно код ответа или код команды для data-response
+2. `payload` (`N` bytes, может быть 0)
+3. `crc32` (4 bytes, little-endian) по данным `response_code + payload`
+
+### CRC
+
+- CRC-32 (software), полином: `0xEDB88320`
+- Init: `0xFFFFFFFF`
+- Final XOR: `0xFFFFFFFF`
+- Порядок CRC-байтов в пакете: little-endian
+
+### Коды ответа
+
+- `0x12` = `RESP_SUCCESS`
+- `0x13` = `RESP_FAILED`
+- `0x14` = `RESP_INVALID` (ошибка формата/CRC)
+
+---
+
+## 2. Команды (host -> device)
+
+## 2.1 Read-only
+
+- `0x01` `CMD_GET_INFO`
+ - Arg: none
+ - Response: `response_code = 0x01`, payload = `InfoPacket_t`
+
+- `0x02` `CMD_GET_GBT_STATUS`
+ - Arg: none
+ - Response: `response_code = 0x02`, payload = `GBT_MonitorPacket_t`
+
+- `0x03` `CMD_GET_CCS_STATUS`
+ - Arg: none
+ - Response: `response_code = 0x03`, payload = `CCS_MonitorPacket_t`
+
+## 2.2 GBT control
+
+- `0x10` `CMD_GBT_CC_ENABLE`
+ - Arg: `uint8_t enable` (`0/1`)
+ - Action: `RELAY_CC` write
+ - Ack: `RESP_SUCCESS/RESP_FAILED`
+
+- `0x11` `CMD_GBT_STOP`
+ - Arg: none
+ - Action: `CONN[0].connControl = CMD_STOP`
+ - Ack: `RESP_SUCCESS/RESP_FAILED`
+
+- `0x12` `CMD_GBT_SET_SOC`
+ - Arg: `uint8_t soc`
+ - Action: `CONN[0].SOC = soc`
+ - Ack: `RESP_SUCCESS/RESP_FAILED`
+
+- `0x13` `CMD_GBT_SET_REQUEST`
+ - Arg: `EvSetLimits_t`
+ - `uint16_t requestedVoltage`
+ - `uint16_t requestedCurrent`
+ - Action: запись в `CONN[0].RequestedVoltage/RequestedCurrent`
+ - Ack: `RESP_SUCCESS/RESP_FAILED`
+
+- `0x14` `CMD_GBT_ENABLE_LOAD`
+ - Arg: `uint8_t enable` (`0/1`)
+ - Action:
+ - `CONN[0].enableLoad`
+ - `CONN[0].ContactorEnabled`
+ - Ack: `RESP_SUCCESS/RESP_FAILED`
+
+- `0x18` `CMD_GBT_SET_VIN`
+ - Arg: `uint8_t vin[17]`
+ - Action: копирование в `GBT_EVInfo.EVIN`
+ - Ack: `RESP_SUCCESS/RESP_FAILED`
+
+## 2.3 CCS control
+
+- `0x20` `CMD_CCS_SET_STATE`
+ - Arg: `uint8_t cp_state_enum`
+ - Action: `cp_state = (CP_State_t)arg`
+ - Ack: `RESP_SUCCESS/RESP_FAILED`
+
+- `0x24` `CMD_CCS_ENABLE_LOAD`
+ - Arg: `uint8_t enable` (`0/1`)
+ - Action:
+ - `CONN[1].enableLoad`
+ - `CONN[1].ContactorEnabled`
+ - Ack: `RESP_SUCCESS/RESP_FAILED`
+
+---
+
+## 3. Payload structures (packed)
+
+Все структуры передаются как `__attribute__((packed))`, little-endian для multi-byte полей.
+
+### 3.1 `InfoPacket_t` (GET_INFO)
+
+- `uint16_t serialNumber`
+- `uint8_t boardVersion`
+- `uint8_t stationType`
+- `uint16_t fw_version_major`
+- `uint16_t fw_version_minor`
+- `uint16_t fw_version_patch`
+
+### 3.2 `GBT_MonitorPacket_t` (GET_GBT_STATUS)
+
+- `uint8_t connector_type` (`0x01`)
+- `uint16_t requestedVoltage`
+- `uint16_t requestedCurrent`
+- `uint16_t measuredVoltageSE`
+- `uint16_t measuredCurrentSE`
+- `uint16_t measuredVoltage`
+- `uint16_t measuredCurrent`
+- `uint8_t cc_enabled`
+- `uint8_t contactorEnabled`
+- `CONN_Error_t chargingError` (`uint8_t`)
+- `uint8_t EvseConnected`
+- `uint8_t soc`
+- `uint8_t vin[17]`
+- `uint8_t cc_state`
+- `CONN_State_t connState` (`uint8_t`)
+
+### 3.3 `CCS_MonitorPacket_t` (GET_CCS_STATUS)
+
+- `uint8_t connector_type` (`0x02`)
+- `uint16_t measuredVoltage`
+- `uint16_t measuredCurrent`
+- `uint8_t cp_enabled`
+- `uint8_t contactorEnabled`
+- `CONN_Error_t chargingError` (`uint8_t`)
+- `uint8_t EvseConnected`
+- `uint8_t soc`
+- `uint8_t cp_state`
+- `uint8_t cp_pwm_duty`
+- `CONN_State_t connState` (`uint8_t`)
+
+---
+
+## 4. Валидация команд
+
+- Для каждой команды проверяется `argument_length` (по фактическому размеру аргумента).
+- Если длина неверная: ответ `RESP_FAILED`.
+- Если пакет не проходит parse/CRC: ответ `RESP_INVALID`.
+
+---
+
+## 5. Пример (логический)
+
+`CMD_GBT_SET_SOC = 0x12`, `soc = 80`:
+
+- TX body: `[0x12, 0x50]`
+- TX full: `[0x12, 0x50, crc0, crc1, crc2, crc3]`
+- RX (ack): `[0x12, crc0, crc1, crc2, crc3]`
+