Чет работает

This commit is contained in:
2025-12-16 17:57:59 +03:00
commit 260a6416ad
2906 changed files with 982301 additions and 0 deletions

View File

@@ -0,0 +1,296 @@
/**
*******************************************************************************
* @file modbus_diag.c
* @brief Реализация диагностики устройства Modbus
*******************************************************************************
* @details
Модуль обработки запросов диагностической информации (0x08):
- Полная поддержка всех подфункций диагностики согласно спецификации Modbus
- Выставление любого бита в Diagnostics Register
- Сбор статистики работы устройства
- Управление режимами работы (Normal/Listen Only)
******************************************************************************/
#include "modbus_diag.h"
#ifdef MODBUS_ENABLE_DIAGNOSTICS
MB_DiagnosticsInfoTypeDef MB_DIAG = {0}; ///< Глобальная структура диагностики
/**
* @brief Инициализация диагностических счетчиков
*/
void MB_DiagnosticsInit(void)
{
MB_DIAG.DiagnosticRegister = 0;
MB_DIAG.DeviceMode = MODBUS_NORMAL_MODE;
// Инициализация счетчиков
MB_DIAG.Counters.BusMessage = 0;
MB_DIAG.Counters.BusCommunicationErr = 0;
MB_DIAG.Counters.BusExceptionErr = 0;
MB_DIAG.Counters.SlaveMessage = 0;
MB_DIAG.Counters.SlaveNoResponse = 0;
MB_DIAG.Counters.SlaveNAK = 0;
MB_DIAG.Counters.SlaveBusy = 0;
MB_DIAG.Counters.BusCharacterOverrun = 0;
}
/**
* @brief Выставить бит в регистре диагностике
* @param bit_num Номер бита для выставления (1-15, 0 бит нельзя выставить)
* @param bit_state Состояние бита для выставления (Выставить/Сбросить)
* @return >0 - номер выставленного бита, 0 - ошибка
*/
int MB_Diagnostics_WriteBit(int bit_num, int bit_state)
{
if(bit_num == 0 || bit_num > 15)
return 0;
if(bit_state)
MB_DIAG.DiagnosticRegister |= (1 << bit_num);
else
MB_DIAG.DiagnosticRegister &= ~(1 << bit_num);
return bit_num;
}
/**
* @brief Прочитать состояние бита диагностического регистра
* @param bit_num Номер бита (0-15)
* @return 1 - бит установлен, 0 - бит сброшен или ошибка
*/
int MB_Diagnostics_GetBit(int bit_num)
{
if(bit_num < 0 || bit_num > 15)
return 0;
return (MB_DIAG.DiagnosticRegister >> bit_num) & 0x01;
}
/**
* @brief Обработать функцию Diagnostics (Serial Line only) (0x08)
* @param modbus_msg Указатель на структуру сообщения modbus
* @return fMessageHandled Статус обработки команды
*/
uint8_t MB_Process_Diagnostics(RS_MsgTypeDef *modbus_msg)
{
uint16_t sub_function = modbus_msg->MbData[0];
uint16_t request_data = modbus_msg->MbData[1];
// Если устройство в режиме Listen Only, отвечаем только на sub-function 0x01
if (MB_DIAG.DeviceMode == MODBUS_LISTEN_ONLY_MODE && sub_function != 0x0001)
{
return 0; // Не отвечаем в режиме Listen Only
}
switch(sub_function)
{
case 0x0000: // Return Query Data
// Эхо-ответ с теми же данными
modbus_msg->MbData[0] = sub_function;
modbus_msg->MbData[1] = request_data;
modbus_msg->ByteCnt = 4;
break;
case 0x0001: // Restart Communications
// Перезапуск коммуникаций - выходим из Listen Only режима
MB_DIAG.DeviceMode = MODBUS_NORMAL_MODE;
// Если request_data = 0xFF00, очищаем лог событий
if (request_data == 0xFF00)
{
MB_DiagnosticsInit(); // Полный сброс
}
else
{
// Очищаем только счетчики, но не регистр диагностики
MB_DIAG.Counters.BusMessage = 0;
MB_DIAG.Counters.BusCommunicationErr = 0;
MB_DIAG.Counters.BusExceptionErr = 0;
MB_DIAG.Counters.SlaveMessage = 0;
MB_DIAG.Counters.SlaveNoResponse = 0;
MB_DIAG.Counters.SlaveNAK = 0;
MB_DIAG.Counters.SlaveBusy = 0;
MB_DIAG.Counters.BusCharacterOverrun = 0;
}
modbus_msg->MbData[0] = sub_function;
modbus_msg->MbData[1] = request_data;
modbus_msg->ByteCnt = 4;
break;
case 0x0002: // Return Diagnostic Register
modbus_msg->MbData[0] = sub_function;
modbus_msg->MbData[1] = MB_DIAG.DiagnosticRegister;
modbus_msg->ByteCnt = 4;
break;
case 0x0003: // Change ASCII Input Delimiter
// В RTU режиме не поддерживается
modbus_msg->FuncCode |= FC_ERR_VALUES_START;
modbus_msg->Except_Code = ET_ILLEGAL_FUNCTION;
return 0;
case 0x0004: // Force Listen Only Mode
MB_DIAG.DeviceMode = MODBUS_LISTEN_ONLY_MODE;
// В режиме Listen Only не отправляем ответ
return 0;
case 0x000A: // Clear Counters and Diagnostic Register
MB_DiagnosticsInit(); // Полный сброс
modbus_msg->MbData[0] = sub_function;
modbus_msg->MbData[1] = 0;
modbus_msg->ByteCnt = 4;
break;
case 0x000B: // Return Bus Message Count
modbus_msg->MbData[0] = sub_function;
modbus_msg->MbData[1] = MB_DIAG.Counters.BusMessage;
modbus_msg->ByteCnt = 4;
break;
case 0x000C: // Return Bus Communication Error Count
modbus_msg->MbData[0] = sub_function;
modbus_msg->MbData[1] = MB_DIAG.Counters.BusCommunicationErr;
modbus_msg->ByteCnt = 4;
break;
case 0x000D: // Return Bus Exception Error Count
modbus_msg->MbData[0] = sub_function;
modbus_msg->MbData[1] = MB_DIAG.Counters.BusExceptionErr;
modbus_msg->ByteCnt = 4;
break;
case 0x000E: // Return Server Message Count
modbus_msg->MbData[0] = sub_function;
modbus_msg->MbData[1] = MB_DIAG.Counters.SlaveMessage;
modbus_msg->ByteCnt = 4;
break;
case 0x000F: // Return Slave No Response Count
modbus_msg->MbData[0] = sub_function;
modbus_msg->MbData[1] = MB_DIAG.Counters.SlaveNoResponse;
modbus_msg->ByteCnt = 4;
break;
case 0x0010: // Return Slave NAK Count
modbus_msg->MbData[0] = sub_function;
modbus_msg->MbData[1] = MB_DIAG.Counters.SlaveNAK;
modbus_msg->ByteCnt = 4;
break;
case 0x0011: // Return Slave Busy Count
modbus_msg->MbData[0] = sub_function;
modbus_msg->MbData[1] = MB_DIAG.Counters.SlaveBusy;
modbus_msg->ByteCnt = 4;
break;
case 0x0012: // Return Bus Character Overrun Count
modbus_msg->MbData[0] = sub_function;
modbus_msg->MbData[1] = MB_DIAG.Counters.BusCharacterOverrun;
modbus_msg->ByteCnt = 4;
break;
case 0x0014: // Clear Overrun Counter and Flag
MB_DIAG.Counters.BusCharacterOverrun = 0;
// Сбрасываем флаг переполнения в DiagnosticRegister
MB_DIAG.DiagnosticRegister &= ~(1<<0);
modbus_msg->MbData[0] = sub_function;
modbus_msg->MbData[1] = 0;
modbus_msg->ByteCnt = 4;
break;
default:
modbus_msg->FuncCode |= FC_ERR_VALUES_START;
modbus_msg->Except_Code = ET_ILLEGAL_FUNCTION;
return 0;
}
return 1;
}
/**
* @brief Увеличивает счетчик сообщений на шине
*/
void MB_Diagnostics_BusMessageCnt(void)
{
MB_DIAG.Counters.BusMessage++;
}
/**
* @brief Увеличивает счетчик ошибок связи
*/
void MB_Diagnostics_CommunicationErrorCnt(void)
{
if (MB_DIAG.Counters.BusCommunicationErr < 0xFFFF)
MB_DIAG.Counters.BusCommunicationErr++;
}
/**
* @brief Увеличивает счетчик исключений
*/
void MB_Diagnostics_ExceptionErrorCnt(void)
{
if (MB_DIAG.Counters.BusExceptionErr < 0xFFFF)
MB_DIAG.Counters.BusExceptionErr++;
}
/**
* @brief Увеличивает счетчик переполнения символов
*/
void MB_Diagnostics_CharacterOverrunCnt(void)
{
if (MB_DIAG.Counters.BusCharacterOverrun < 0xFFFF)
{
MB_DIAG.Counters.BusCharacterOverrun++;
// Устанавливаем флаг переполнения в DiagnosticRegister
MB_DIAG.DiagnosticRegister |= (1 << 0);
}
}
/**
* @brief Увеличивает счетчик отсутствия ответов
*/
void MB_Diagnostics_SlaveMessageCnt(void)
{
if (MB_DIAG.Counters.SlaveMessage < 0xFFFF)
MB_DIAG.Counters.SlaveMessage++;
}
/**
* @brief Увеличивает счетчик отсутствия ответов
*/
void MB_Diagnostics_SlaveNoResponseCnt(void)
{
if (MB_DIAG.Counters.SlaveNoResponse < 0xFFFF)
MB_DIAG.Counters.SlaveNoResponse++;
}
/**
* @brief Увеличивает счетчик NAK ответов
*/
void MB_Diagnostics_SlaveNAKCnt(void)
{
if (MB_DIAG.Counters.SlaveNAK < 0xFFFF)
MB_DIAG.Counters.SlaveNAK++;
}
/**
* @brief Увеличивает счетчик занятости устройства
*/
void MB_Diagnostics_SlaveBusyCnt(void)
{
if (MB_DIAG.Counters.SlaveBusy < 0xFFFF)
MB_DIAG.Counters.SlaveBusy++;
}
/**
* @brief Получение текущего режима устройства
* @return Текущий режим работы устройства
*/
MB_DeviceModeTypeDef MB_GetDeviceMode(void)
{
return MB_DIAG.DeviceMode;
}
#endif //MODBUS_ENABLE_DIAGNOSTICS