/* * 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 "usart.h" #include #include #include "serial_control.h" // Кольцевой буфер для отладочных сообщений #define DEBUG_BUFFER_SIZE 1024 #define DEBUG_BUFFER_MAX_COUNT 128 typedef struct { uint8_t buffer[DEBUG_BUFFER_SIZE]; volatile uint16_t write_index; volatile uint16_t read_index; volatile uint16_t count; } DebugBuffer_t; static DebugBuffer_t debug_buffer = { .buffer = {0}, .write_index = 0, .read_index = 0, .count = 0 }; #if defined(__GNUC__) int _write(int fd, char * ptr, int len) { debug_buffer_add((const uint8_t*)ptr, len); return len; } #endif // Добавляет данные в кольцевой буфер void debug_buffer_add(const uint8_t* data, uint16_t 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 + 1) % DEBUG_BUFFER_SIZE; debug_buffer.count--; } debug_buffer.buffer[debug_buffer.write_index] = data[i]; debug_buffer.write_index = (debug_buffer.write_index + 1) % DEBUG_BUFFER_SIZE; debug_buffer.count++; } __enable_irq(); } // Возвращает количество доступных данных в буфере uint16_t debug_buffer_available(void) { __disable_irq(); uint16_t count = debug_buffer.count; __enable_irq(); return count; } // Отправляет один пакет данных из буфера через SC_SendPacket (не более 250 байт) void debug_buffer_send(void) { __disable_irq(); // Если буфер пуст, ничего не делаем if (debug_buffer.count == 0) { __enable_irq(); return; } // Определяем сколько байт можно отправить (не более 250) 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; // Отправляем только непрерывный блок (до конца буфера или до bytes_to_send) 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(); } #define LOG_BUFFER_SIZE 128 uint8_t log_buffer[LOG_BUFFER_SIZE]; // Кастомный printf с приоритетом лога int log_printf(LogLevel_t level, const char *format, ...) { va_list args; int result; // Добавляем приоритет первым байтом log_buffer[0] = (uint8_t)level; // Форматируем строку начиная со второго байта va_start(args, format); result = vsnprintf((char*)&log_buffer[1], LOG_BUFFER_SIZE - 2, format, args); va_end(args); // Проверяем, не переполнился ли буфер if (result < 0) { return result; } // Ограничиваем размер, чтобы оставить место для нуль-терминатора if (result >= (LOG_BUFFER_SIZE - 2)) { result = LOG_BUFFER_SIZE - 2; } // Добавляем нуль-терминатор в конец log_buffer[result + 1] = '\0'; // Отправляем в буфер (приоритет + строка + нуль-терминатор) debug_buffer_add(log_buffer, result + 2); return result; } #ifndef USE_WEB_INTERFACE extern UART_HandleTypeDef huart2; uint8_t debug_rx_buffer[256]; uint8_t debug_cmd_received; uint8_t debug_rx_buffer_size = 0; 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_rx_interrupt(UART_HandleTypeDef *huart, uint16_t Size){ debug_rx_buffer[Size] = '\0'; debug_rx_buffer_size = Size; debug_cmd_received = 1; } void debug_init(){ HAL_UARTEx_ReceiveToIdle_IT(&huart2,debug_rx_buffer,255); } 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) { log_printf(LOG_INFO, "Resetting...\n"); NVIC_SystemReset(); } else if (strncmp((const char*)buffer, "relayaux", length) == 0) { log_printf(LOG_INFO, "Relaying...\n"); RELAY_Write(RELAY_AUX, 1); HAL_Delay(2000); RELAY_Write(RELAY_AUX, 0); } else if (strncmp((const char*)buffer, "relaycc", length) == 0) { log_printf(LOG_INFO, "Relaying...\n"); RELAY_Write(RELAY_CC, 1); HAL_Delay(200); RELAY_Write(RELAY_CC, 0); } else if (strncmp((const char*)buffer, "relaydc", length) == 0) { log_printf(LOG_INFO, "Relaying...\n"); RELAY_Write(RELAY_DC, 1); HAL_Delay(200); RELAY_Write(RELAY_DC, 0); } else if (strncmp((const char*)buffer, "relayac", length) == 0) { log_printf(LOG_INFO, "Relaying...\n"); RELAY_Write(RELAY_AC, 1); HAL_Delay(200); RELAY_Write(RELAY_AC, 0); } else if (strncmp((const char*)buffer, "adc", length) == 0) { log_printf(LOG_INFO, "CC1=%.2f\n", CONN_CC_GetAdc()); } else if (strncmp((const char*)buffer, "lock_state", length) == 0) { log_printf(LOG_INFO, "Lock state=%d\n", GBT_LockGetState()); } else if (strncmp((const char*)buffer, "lock_lock", length) == 0) { log_printf(LOG_INFO, "Locked\n"); GBT_Lock(1); } else if (strncmp((const char*)buffer, "lock_unlock", length) == 0) { log_printf(LOG_INFO, "Unlocked\n"); GBT_Lock(0); } else if (strncmp((const char*)buffer, "complete", length) == 0) { CONN_SetState(Finished); } else if (strncmp((const char*)buffer, "start", length) == 0) { log_printf(LOG_INFO, "Started\n"); GBT_Start(); } else if (strncmp((const char*)buffer, "stop", length) == 0) { log_printf(LOG_INFO, "Stopped\n"); GBT_StopEVSE(GBT_CST_SUSPENDS_ARTIFICIALLY); } else if (strncmp((const char*)buffer, "stop1", length) == 0) { log_printf(LOG_INFO, "Stopped\n"); GBT_ForceStop(); // } else if (strncmp((const char*)buffer, "force", length) == 0) { // log_printf(LOG_INFO, "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: log_printf(LOG_INFO, "GBT_CC_UNKNOWN\n"); break; case GBT_CC_12V: log_printf(LOG_INFO, "GBT_CC_12V\n"); break; case GBT_CC_6V: log_printf(LOG_INFO, "GBT_CC_6V\n"); break; case GBT_CC_4V: log_printf(LOG_INFO, "GBT_CC_4V\n"); break; case GBT_CC_2V: log_printf(LOG_INFO, "GBT_CC_2V\n"); break; } } else if (strncmp((const char*)buffer, "temp", length) == 0) { log_printf(LOG_INFO, "temp1 %d\n",GBT_ReadTemp(0)); log_printf(LOG_INFO, "temp2 %d\n",GBT_ReadTemp(1)); } else if (strncmp((const char*)buffer, "info1", length) == 0) { log_printf(LOG_INFO, "Battery info:\n"); log_printf(LOG_INFO, "maxCV %dV\n",GBT_BATStat.maxCellVoltage/100); // 0.01v/bit log_printf(LOG_INFO, "maxCC %dA\n",GBT_BATStat.maxChargingCurrent/10); // 0.1A/bit log_printf(LOG_INFO, "totE %dkWh\n",GBT_BATStat.totalEnergy/10); // 0.1kWh log_printf(LOG_INFO, "maxCV %dV\n",GBT_BATStat.maxChargingVoltage/10); // 0.1V/ bit log_printf(LOG_INFO, "maxT %dC\n",(int16_t)GBT_BATStat.maxTemp-50); // 1C/bit, -50C offset log_printf(LOG_INFO, "SOC %dp\n",GBT_BATStat.SOC/10); // 0.1%/bit , 0..100% log_printf(LOG_INFO, "Volt. %dV\n",GBT_BATStat.measVoltage/10); // 0.1V/bit } else if (strncmp((const char*)buffer, "info2", length) == 0) { log_printf(LOG_INFO, "EV info:\n"); log_printf(LOG_INFO, "GBT_ver V%d.%d%d\n",GBT_EVInfo.version[0],GBT_EVInfo.version[1],GBT_EVInfo.version[2]); log_printf(LOG_INFO, "Battery type: %d\n",GBT_EVInfo.batteryType); log_printf(LOG_INFO, "Battery capacity: %d\n", GBT_EVInfo.batteryCapacity); // 0.1Ah/bit log_printf(LOG_INFO, "Battery voltage: %d\n", GBT_EVInfo.batteryVoltage); // 0.1V/bit log_printf(LOG_INFO, "Battery vendor: %.4s\n", GBT_EVInfo.batteryVendor); // Battery vendor (ASCII string) log_printf(LOG_INFO, "Battery SN: %lu\n", GBT_EVInfo.batterySN); // int log_printf(LOG_INFO, "Battery manufacture date: %02d.%02d.%04d\n", GBT_EVInfo.batteryManuD, GBT_EVInfo.batteryManuM ,GBT_EVInfo.batteryManuY+1985); // year (offset 1985) log_printf(LOG_INFO, "Battery cycles: %d\n", GBT_EVInfo.batteryCycleCount); //uint24_t log_printf(LOG_INFO, "Own auto: %d\n", GBT_EVInfo.ownAuto); // 0 = lizing, 1 = own auto log_printf(LOG_INFO, "EVIN: %.17s\n", GBT_EVInfo.EVIN); //EVIN log_printf(LOG_INFO, "EV_SW_VER: %.8s\n", GBT_EVInfo.EV_SW_VER); } else if (strncmp((const char*)buffer, "info3", length) == 0) { log_printf(LOG_INFO, "GBT_MaxLoad info:\n"); log_printf(LOG_INFO, "Output max current: %d\n",GBT_MaxLoad.maxOutputCurrent); log_printf(LOG_INFO, "Output min current: %d\n",GBT_MaxLoad.minOutputCurrent); log_printf(LOG_INFO, "Output max voltage: %d\n",GBT_MaxLoad.maxOutputVoltage); log_printf(LOG_INFO, "Output min voltage: %d\n",GBT_MaxLoad.minOutputVoltage); log_printf(LOG_INFO, "\nGBT_ChargerInfo info:\n"); log_printf(LOG_INFO, "BMS Recognized: %d\n",GBT_ChargerInfo.bmsIdentified); log_printf(LOG_INFO, "Charger location: %.3s\n",GBT_ChargerInfo.chargerLocation); log_printf(LOG_INFO, "Charger number: %lu\n",GBT_ChargerInfo.chargerNumber); } else if (strncmp((const char*)buffer, "help", length) == 0) { log_printf(LOG_INFO, "Command list:\n"); log_printf(LOG_INFO, "reset\n"); log_printf(LOG_INFO, "help\n"); log_printf(LOG_INFO, "cc_state\n"); log_printf(LOG_INFO, "lock_lock\n"); log_printf(LOG_INFO, "lock_unlock\n"); log_printf(LOG_INFO, "lock_state\n"); log_printf(LOG_INFO, "adc\n"); log_printf(LOG_INFO, "relay(cc,aux,ac,dc)\n"); log_printf(LOG_INFO, "start\n"); log_printf(LOG_INFO, "stop\n"); log_printf(LOG_INFO, "stop1\n"); // log_printf(LOG_INFO, "force\n"); log_printf(LOG_INFO, "temp\n"); log_printf(LOG_INFO, "info1\n"); log_printf(LOG_INFO, "info2\n"); log_printf(LOG_INFO, "info3\n"); log_printf(LOG_INFO, "time\n"); log_printf(LOG_INFO, "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); log_printf(LOG_INFO, "Year: %d\n", parts->tm_year + 1900); log_printf(LOG_INFO, "Month: %d\n", parts->tm_mon + 1); log_printf(LOG_INFO, "Day: %d\n", parts->tm_mday); log_printf(LOG_INFO, "Hour: %d\n", parts->tm_hour); log_printf(LOG_INFO, "Minute: %d\n", parts->tm_min); log_printf(LOG_INFO, "Second: %d\n", parts->tm_sec); } else if (strncmp((const char*)buffer, "cantest", length) == 0) { //GBT_SendCHM(); GBT_Error(0xFDF0C0FC); //BRM Timeout log_printf(LOG_INFO, "can test\n"); } else { log_printf(LOG_INFO, "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; } } #else #endif // USE_WEB_INTERFACE