release 0.2

Добавлен модуль диагностически модбас (функция 0x08)

+ мелкие кореркции
This commit is contained in:
2025-11-04 13:05:52 +03:00
parent 423f6c2918
commit bd34ace028
11 changed files with 552 additions and 99 deletions

View File

@@ -27,7 +27,7 @@
//----------------Прием модбас----------------//
#include "modbus.h"
MODBUS_SetupHardware(&hmodbus1, &huart1, &htim3);
MODBUS_FirstInit(&hmodbus1, &huart1, &htim3);
MODBUS_SlaveStart(&hmodbus1, NULL);
// или если нужно переключится на другой
@endverbatim
@@ -68,6 +68,7 @@ MODBUS_SlaveStart(&hmodbus1, NULL);
#include "modbus_holdregs.h"
#include "modbus_inputregs.h"
#include "modbus_devid.h"
#include "modbus_diag.h"
@@ -83,11 +84,11 @@ MODBUS_SlaveStart(&hmodbus1, NULL);
@{
*/
/* Инициализация периферии модбас. */
void MODBUS_SetupHardware(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim);
HAL_StatusTypeDef MODBUS_FirstInit(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim);
/* Программная конфигурация модбас. */
void MODBUS_Config(RS_HandleTypeDef *hmodbus, uint8_t ID, uint16_t Timeout, uint8_t master);
HAL_StatusTypeDef MODBUS_Config(RS_HandleTypeDef *hmodbus, uint8_t ID, uint16_t Timeout, uint8_t master);
/* Запуск слейв устройства */
void MODBUS_SlaveStart(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg);
HAL_StatusTypeDef MODBUS_SlaveStart(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg);
/** MODBUS_INIT_FUNCTIONS
* @}
*/

View File

@@ -81,7 +81,7 @@ typedef enum
/**
* @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS Modbus Data Access
* @ingroup MODBUS_FUNCTIONS
* @brief Функции для доступа к данным модбас (коилы)
* @brief Функции для доступа к данным модбас
@{
*/

View File

@@ -1,7 +1,7 @@
/**
******************************************************************************
* @file modbus_devid.h
* @brief Идентификация устройства Modbus
* @brief Идентификаторы устройства Modbus
******************************************************************************
@addtogroup MODBUS_DEVID Device Identificators Tools
@ingroup MODBUS_INTERNAL
@@ -53,30 +53,6 @@ extern MB_DeviceIdentificationTypeDef MB_DEVID;
void MB_DeviceInentificationInit(void);
///////////////---DEVICE IDENTIVICATIONS DEFINES---//////////////////
/////////////////////////////////////////////////////////////////////
/////////////////---DEVICE DIAGNOSTICS DEFINES---////////////////////
/** @brief Структура со диагностической информацией устройства модбас */
typedef struct
{
uint16_t DiagnosticRegister;
struct
{
uint16_t BusMessage;
uint16_t BusCommunicationErr;
uint16_t BusExceptionErr;
uint16_t SlaveMessage;
uint16_t SlaveNoResponse;
uint16_t SlaveNAK;
uint16_t SlaveBusy;
uint16_t BusCharacterOverrun;
}Counters;
}MB_DiagnosticsInfoTypeDef;
extern MB_DiagnosticsInfoTypeDef MB_DINFO;
/////////////////---DEVICE DIAGNOSTICS DEFINES---////////////////////
/////////////////////////////////////////////////////////////////////
////////////////////---MODBUS FUNCTION DEFINES---////////////////////

107
Inc/modbus_diag.h Normal file
View File

@@ -0,0 +1,107 @@
/**
******************************************************************************
* @file modbus_diag.h
* @brief Диагностика устройства Modbus
******************************************************************************
@addtogroup MODBUS_DIAG Diagnostics Tools
@ingroup MODBUS_INTERNAL
@{
******************************************************************************
* @details
Модуль реализации Diagnostics (Serial Line only) (0x08):
- Полная поддержка всех подфункций диагностики
- Возможность выставить/сбросить любой бит в диагностическом регистре
- Сбор статистики работы устройства
- Управление режимами работы
******************************************************************************/
#ifndef __MODBUS_DIAG_H_
#define __MODBUS_DIAG_H_
#include "modbus_core.h"
/////////////////////////////////////////////////////////////////////
/////////////////---DEVICE DIAGNOSTICS DEFINES---////////////////////
/** @brief Режимы работы устройства */
typedef enum
{
MODBUS_NORMAL_MODE = 0,
MODBUS_LISTEN_ONLY_MODE = 1
} MB_DeviceModeTypeDef;
/** @brief Структура со диагностической информацией устройства модбас */
typedef struct
{
uint16_t DiagnosticRegister;
MB_DeviceModeTypeDef DeviceMode;
uint8_t AsciiDelimiter;
struct
{
uint16_t BusMessage;
uint16_t BusCommunicationErr;
uint16_t BusExceptionErr;
uint16_t SlaveMessage;
uint16_t SlaveNoResponse;
uint16_t SlaveNAK;
uint16_t SlaveBusy;
uint16_t BusCharacterOverrun;
} Counters;
} MB_DiagnosticsInfoTypeDef;
extern MB_DiagnosticsInfoTypeDef MB_DIAG;
/////////////////---DEVICE DIAGNOSTICS DEFINES---////////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////////---FUNCTIONS---/////////////////////////////
/* Инициализация диагностических счетчиков */
void MB_DiagnosticsInit(void);
/**
* @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS Modbus Data Access
@{
*/
/* Выставить бит в регистре диагностике */
int MB_Diagnostics_WriteBit(int bit_num, int bit_state);
/*ь Прочитать состояние бита диагностического регистра */
int MB_Diagnostics_GetBit(int bit_num);
/* Получение текущего режима устройства */
MB_DeviceModeTypeDef MB_GetDeviceMode(void);
/** MODBUS_CMD_PROCESS_FUNCTIONS
* @}
*/
//---------PROCESS MODBUS COMMAND FUNCTIONS---------
/**
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
@{
*/
/* Обработка команды диагностики (0x08) */
uint8_t MB_Proccess_Diagnostics(RS_MsgTypeDef *modbus_msg);
/** MODBUS_CMD_PROCESS_FUNCTIONS
* @}
*/
/* Функции для обновления счетчиков диагностики */
void MB_Diagnostics_BusMessageCnt(void);
void MB_Diagnostics_CommunicationErrorCnt(void);
void MB_Diagnostics_ExceptionErrorCnt(void);
void MB_Diagnostics_CharacterOverrunCnt(void);
void MB_Diagnostics_SlaveMessageCnt(void);
void MB_Diagnostics_SlaveNoResponseCnt(void);
void MB_Diagnostics_SlaveNAKCnt(void);
void MB_Diagnostics_SlaveBusyCnt(void);
/////////////////////////---FUNCTIONS---/////////////////////////////
#endif //__MODBUS_DIAG_H_
/** MODBUS_DIAG
* @}
*/

View File

@@ -33,7 +33,7 @@ Modbus/
1. **Склонируйте субмодуль** в ваш проект:
```bash
git submodule add https://git.arktika.cyou/Razvalyaev/STM32_ExtendedLibs path/to/ExtendedLibs
git submodule add https://git.arktika.cyou/set506/STM32_Modbus path/to/Modbus
git submodule update --init --recursive
```

View File

@@ -9,8 +9,9 @@
@section Функции и макросы
### Инициализация:
- MODBUS_SetupHardware() — Инициализация модуля Modbus.
- MODBUS_FirstInit() — Инициализация модуля Modbus.
- MODBUS_Config() — Инициализация модуля Modbus.
- MODBUS_SlaveStart() — Запуск Modbus как Slave.
### Функции для Modbus
- MB_Slave_Response()
@@ -22,45 +23,50 @@
### Функции для работы с RS (UART):
- RS_Parse_Message() / RS_Collect_Message() — Парсинг и сборка сообщения.
- RS_Response() — Отправка ответа.
******************************************************************************/
#include "modbus.h"
/* MODBUS HANDLES */
RS_HandleTypeDef hmodbus1;
RS_MsgTypeDef MODBUS_MSG;
RS_HandleTypeDef hmodbus1; ///< Default Handle for Modbus
RS_MsgTypeDef MODBUS_MSG; ///< Default Message Struct for Modbus
/* DEFINE REGISTERS/COILS */
MB_DeviceIdentificationTypeDef MB_DEVID;
MB_DataStructureTypeDef MB_DATA = {0};;
/* DEFINE DATA FOR MODBUS */
MB_DataStructureTypeDef MB_DATA = {0};; ///< Coils & Registers
//-------------------------------------------------------------------
//-----------------------------FOR USER------------------------------
/**
* @brief Инициализация периферии модбас.
* @param hmodbus Указатель на хендлер RS
* @param huart Указатель на хендлер UART
* @param htim Указатель на хендлер TIM
* @details Подключает хендлы периферии к hmodbus
* Конфигурация выставляется по умолчанию из modbus_config.h
*/
void MODBUS_SetupHardware(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim)
HAL_StatusTypeDef MODBUS_FirstInit(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim)
{
if((hmodbus == NULL) || (huart == NULL))
{
return;
return HAL_ERROR;
}
MB_DeviceInentificationInit();
MB_DiagnosticsInit();
//-----------SETUP MODBUS-------------
// set up modbus: MB_RX_Size_NotConst and Timeout enable
hmodbus1.ID = MODBUS_DEVICE_ID;
hmodbus1.sRS_Timeout = MODBUS_TIMEOUT;
hmodbus1.sRS_Mode = RS_SLAVE_ALWAYS_WAIT;
hmodbus1.sRS_RX_Size_Mode = RS_RX_Size_NotConst;
hmodbus->ID = MODBUS_DEVICE_ID;
hmodbus->sRS_Timeout = MODBUS_TIMEOUT;
hmodbus->sRS_Mode = RS_SLAVE_ALWAYS_WAIT;
hmodbus->sRS_RX_Size_Mode = RS_RX_Size_NotConst;
// INIT
hmodbus1.RS_STATUS = RS_Init(hmodbus, huart, htim, 0);
hmodbus->RS_STATUS = RS_Init(hmodbus, huart, htim, 0);
RS_EnableReceive();
if(hmodbus->RS_STATUS == RS_OK)
return HAL_OK;
else
return HAL_ERROR;
}
/**
* @brief Программная конфигурация модбас.
@@ -69,11 +75,15 @@ void MODBUS_SetupHardware(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart,
* @param master Режим мастер (пока не сделан)
* @details Конфигурирует ID, таймаут и режим hmodbus
*/
void MODBUS_Config(RS_HandleTypeDef *hmodbus, uint8_t ID, uint16_t Timeout, uint8_t master)
HAL_StatusTypeDef MODBUS_Config(RS_HandleTypeDef *hmodbus, uint8_t ID, uint16_t Timeout, uint8_t master)
{
if(hmodbus == NULL)
{
return;
return HAL_ERROR;
}
if((ID < 1) || (ID > 247))
{
return HAL_ERROR;
}
//-----------SETUP MODBUS-------------
// set up modbus: MB_RX_Size_NotConst and Timeout enable
@@ -84,30 +94,45 @@ void MODBUS_Config(RS_HandleTypeDef *hmodbus, uint8_t ID, uint16_t Timeout, uint
else
hmodbus->sRS_Mode = RS_SLAVE_ALWAYS_WAIT;
hmodbus->sRS_RX_Size_Mode = RS_RX_Size_NotConst;
return HAL_OK;
}
/**
* @brief Запуск слейв модбас.
* @param hmodbus Указатель на хендлер RS.
* @param modbus_msg Указатель на структуру сообщения.
* @param modbus_msg Указатель на структуру сообщения.
(NULL чтобы использовать дефолтную)
* @details Конфигурирует ID, таймаут и режим hmodbus
*/
void MODBUS_SlaveStart(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
HAL_StatusTypeDef MODBUS_SlaveStart(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
{
if(hmodbus == NULL)
{
return;
return HAL_ERROR;
}
if(hmodbus->sRS_Mode >= RS_MASTER_START)
{
return HAL_ERROR;
}
if(modbus_msg)
RS_Receive_IT(hmodbus, modbus_msg);
hmodbus->RS_STATUS = RS_Receive_IT(hmodbus, modbus_msg);
else
RS_Receive_IT(hmodbus, &MODBUS_MSG);
hmodbus->RS_STATUS = RS_Receive_IT(hmodbus, &MODBUS_MSG);
if(hmodbus->RS_STATUS == RS_OK)
return HAL_OK;
else
return HAL_ERROR;
}
//-------------------------------------------------------------------
//-----------------------------INTERNAL------------------------------
/**
* @brief Ответ на сообщение в режиме слейва.
* @param hmodbus Указатель на хендлер RS.
@@ -121,12 +146,15 @@ static RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeD
hmodbus->f.EchoResponse = 0;
RS_Reset_TX_Flags(hmodbus); // reset flag for correct transmit
if(hmodbus->ID == 0)
MB_Diagnostics_BusMessageCnt();
if(hmodbus->ID == 0 || modbus_msg->MbAddr == 0)
{
MB_Diagnostics_SlaveNoResponseCnt(); // <-- Устройство не отвечает на широковещательные сообщения
hmodbus->RS_STATUS = RS_SKIP;
return MB_RES;
return RS_Handle_Receive_Start(hmodbus, modbus_msg);
}
MB_Diagnostics_SlaveMessageCnt();
if(modbus_msg->Func_Code < ERR_VALUES_START)// if no errors after parsing
{
switch (modbus_msg->Func_Code)
@@ -192,12 +220,30 @@ static RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeD
hmodbus->f.MessageHandled = MB_Proccess_Read_Device_Identification(hmodbus->pMessagePtr);
break;
// Добавить в switch-case после других case:
case MB_R_DIAGNOSTIC:
hmodbus->f.MessageHandled = MB_Proccess_Diagnostics(hmodbus->pMessagePtr);
break;
/* unknown func code */
default: modbus_msg->Except_Code = 0x01; /* set exception code: illegal function */
default:
modbus_msg->Except_Code = 0x01; /* set exception code: illegal function */
MB_Diagnostics_SlaveNAKCnt();
}
// Проверяем режим устройства - если Listen Only, не обрабатываем команды
if (MB_GetDeviceMode() == MODBUS_LISTEN_ONLY_MODE)
{
MB_Diagnostics_SlaveNoResponseCnt();
hmodbus->RS_STATUS = RS_SKIP;
return RS_Handle_Receive_Start(hmodbus, modbus_msg);;
}
// Проверяем статус обработки запроса
if(hmodbus->f.MessageHandled == 0)
{
MB_Diagnostics_ExceptionErrorCnt();
TrackerCnt_Warn(hmodbus->rs_err);
modbus_msg->Func_Code |= ERR_VALUES_START;
}
@@ -282,6 +328,14 @@ static RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_M
}
}
else if(modbus_msg->Func_Code == MB_R_DIAGNOSTIC)
{
// Diagnostics special format: [SubFunc_HI][SubFunc_LO][Data_HI][Data_LO]
modbus_uart_buff[ind++] = modbus_msg->DATA[0] >> 8; // Sub-function HI
modbus_uart_buff[ind++] = modbus_msg->DATA[0] & 0xFF; // Sub-function LO
modbus_uart_buff[ind++] = modbus_msg->DATA[1] >> 8; // Data HI
modbus_uart_buff[ind++] = modbus_msg->DATA[1] & 0xFF; // Data LO
}
else // modbus data header
{
// set size of received data
@@ -344,24 +398,23 @@ static int MB_Define_Size_of_Function(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *
RS_StatusTypeDef MB_RES = 0;
int mb_func_size = 0;
if ((modbus_msg->Func_Code & ~ERR_VALUES_START) < 0x0F)
if (modbus_msg->Func_Code == MB_R_DIAGNOSTIC)
{
modbus_msg->ByteCnt = 0;
mb_func_size = 1;
}
else
{
modbus_msg->ByteCnt = hmodbus->pBufferPtr[RX_FIRST_PART_SIZE-1]; // get numb of data in command
// +1 because that defines is size, not ind.
mb_func_size = modbus_msg->ByteCnt + 2;
}
if(modbus_msg->Func_Code == MB_R_DEVICE_INFO)
}
else if(modbus_msg->Func_Code == MB_R_DEVICE_INFO)
{
mb_func_size = 0;
}
else if ((modbus_msg->Func_Code & ~ERR_VALUES_START) < 0x0F)
{
mb_func_size = 1;
}
else
{
mb_func_size = modbus_msg->ByteCnt + 2;
}
mb_func_size = RX_FIRST_PART_SIZE + mb_func_size; // size of whole message
return mb_func_size;
@@ -381,20 +434,25 @@ static RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_Msg
uint32_t check_empty_buff;
int ind = 0; // ind for modbus-uart buffer
hmodbus->f.RX_Continue = 0;
int expected_size = 0;
//-----INFO ABOUT DATA/MESSAGE-------
//-----------[first bits]------------
// get ID of message/user
if(modbus_uart_buff[ind] != hmodbus->ID)
{
modbus_msg->MbAddr = 0;
return RS_SKIP;
ind++;
}
else
{
modbus_msg->MbAddr = modbus_uart_buff[ind++];
}
modbus_msg->MbAddr = modbus_uart_buff[ind++];
// get func code
modbus_msg->Func_Code = modbus_uart_buff[ind++];
if(modbus_msg->Func_Code & ERR_VALUES_START) // явная херня
{
MB_Diagnostics_SlaveNAKCnt();
modbus_msg->MbAddr = 0;
return RS_SKIP;
}
@@ -406,6 +464,18 @@ static RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_Msg
modbus_msg->DevId.NextObjId = modbus_uart_buff[ind++];
modbus_msg->ByteCnt = 0;
}
else if(modbus_msg->Func_Code == MB_R_DIAGNOSTIC)
{
// Diagnostics: читаем 4 байта в DATA[0] и DATA[1]
// Sub-function
modbus_msg->DATA[0] = modbus_uart_buff[ind++] << 8;
modbus_msg->DATA[0] |= modbus_uart_buff[ind++];
// Data
modbus_msg->DATA[1] = modbus_uart_buff[ind++] << 8;
modbus_msg->DATA[1] |= modbus_uart_buff[ind++];
modbus_msg->Addr = 0; // не использует Addr
modbus_msg->Qnt = 0; // не использует Qnt
}
else // if its classic modbus request
{
// get address from CMD
@@ -422,6 +492,20 @@ static RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_Msg
else
hmodbus->pMessagePtr->ByteCnt = 0;
expected_size = MB_Define_Size_of_Function(hmodbus, modbus_msg);
// если размер меньше ожидаемого - продолжаем принимать
if(hmodbus->RS_Message_Size < expected_size)
{
hmodbus->f.RX_Continue = 1;
return RS_SKIP;
}
// если больше Ошибка
else if (hmodbus->RS_Message_Size > expected_size)
{
MB_Diagnostics_CommunicationErrorCnt();
return RS_PARSE_MSG_ERR;
}
//---------------DATA----------------
// (optional)
if (modbus_msg->ByteCnt != 0)
@@ -431,6 +515,7 @@ static RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_Msg
{
TrackerCnt_Err(hmodbus->rs_err);
modbus_msg->Func_Code |= ERR_VALUES_START;
MB_Diagnostics_CommunicationErrorCnt();
return RS_PARSE_MSG_ERR;
}
uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->DATA;
@@ -456,6 +541,7 @@ static RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_Msg
// compare crc
if (modbus_msg->MB_CRC != CRC_VALUE)
{
MB_Diagnostics_CommunicationErrorCnt();
TrackerCnt_Err(hmodbus->rs_err);
modbus_msg->Func_Code |= ERR_VALUES_START;
}
@@ -468,17 +554,6 @@ static RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_Msg
// if(check_empty_buff == 0)
// hmodbus->MB_RESPONSE = MB_EMPTY_MSG; //
// если размер меньше ожидаемого - продолжаем принимать
if(hmodbus->RS_Message_Size < MB_Define_Size_of_Function(hmodbus, modbus_msg))
{
hmodbus->f.RX_Continue = 1;
return RS_SKIP;
}
// если больше Ошибка
else if (hmodbus->RS_Message_Size > MB_Define_Size_of_Function(hmodbus, modbus_msg))
{
return RS_PARSE_MSG_ERR;
}
return RS_OK;
}

View File

@@ -1,7 +1,7 @@
/**
******************************************************************************
* @file modbus_devid.c
* @brief Реализация идентификации устройства Modbus
* @brief Реализация идентификаторов устройства Modbus
******************************************************************************
* @details
Модуль обработки запросов идентификации устройства через MEI-тип 0x0E:
@@ -14,9 +14,10 @@
сообщений с установкой флага MoreFollows и указанием NextObjId для
продолжения чтения в следующем запросе.
******************************************************************************/
#include "modbus_devid.h"
MB_DeviceIdentificationTypeDef MB_DEVID; ///< Device Identificatino=
/**
* @brief Write Object of Device Identification to MessageData
@@ -115,6 +116,11 @@ uint8_t MB_Proccess_Read_Device_Identification(RS_MsgTypeDef *modbus_msg)
break;
case MB_EXTENDED_IDENTIFICATION:
if(MODBUS_NUMB_OF_USEROBJECTS <= 0 || MODBUS_NUMB_OF_USEROBJECTS > 128)
{
return 0;
}
if (modbus_msg->DevId.NextObjId == 0)
{
modbus_msg->DevId.NextObjId = 0x80;

293
Src/modbus_diag.c Normal file
View File

@@ -0,0 +1,293 @@
/**
******************************************************************************
* @file modbus_diag.c
* @brief Реализация диагностики устройства Modbus
******************************************************************************
* @details
Модуль обработки запросов диагностической информации (0x08):
- Полная поддержка всех подфункций диагностики согласно спецификации Modbus
- Выставление любого бита в Diagnostics Register
- Сбор статистики работы устройства
- Управление режимами работы (Normal/Listen Only)
******************************************************************************/
#include "modbus_diag.h"
// Глобальная структура диагностики
MB_DiagnosticsInfoTypeDef MB_DIAG = {0};
/**
* @brief Инициализация диагностических счетчиков
*/
void MB_DiagnosticsInit(void)
{
MB_DIAG.DiagnosticRegister = 0;
MB_DIAG.DeviceMode = MODBUS_NORMAL_MODE;
MB_DIAG.AsciiDelimiter = '\n'; // LF по умолчанию
// Инициализация счетчиков
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 Обработка команды диагностики (0x08)
* @param modbus_msg Указатель на структуру сообщения modbus
* @return fMessageHandled Статус обработки команды
*/
uint8_t MB_Proccess_Diagnostics(RS_MsgTypeDef *modbus_msg)
{
uint16_t sub_function = modbus_msg->DATA[0];
uint16_t request_data = modbus_msg->DATA[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->DATA[0] = sub_function;
modbus_msg->DATA[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->DATA[0] = sub_function;
modbus_msg->DATA[1] = request_data;
modbus_msg->ByteCnt = 4;
break;
case 0x0002: // Return Diagnostic Register
modbus_msg->DATA[0] = sub_function;
modbus_msg->DATA[1] = MB_DIAG.DiagnosticRegister;
modbus_msg->ByteCnt = 4;
break;
case 0x0003: // Change ASCII Input Delimiter
// В RTU режиме не поддерживается
modbus_msg->Func_Code |= ERR_VALUES_START;
modbus_msg->Except_Code = 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->DATA[0] = sub_function;
modbus_msg->DATA[1] = 0;
modbus_msg->ByteCnt = 4;
break;
case 0x000B: // Return Bus Message Count
modbus_msg->DATA[0] = sub_function;
modbus_msg->DATA[1] = MB_DIAG.Counters.BusMessage;
modbus_msg->ByteCnt = 4;
break;
case 0x000C: // Return Bus Communication Error Count
modbus_msg->DATA[0] = sub_function;
modbus_msg->DATA[1] = MB_DIAG.Counters.BusCommunicationErr;
modbus_msg->ByteCnt = 4;
break;
case 0x000D: // Return Bus Exception Error Count
modbus_msg->DATA[0] = sub_function;
modbus_msg->DATA[1] = MB_DIAG.Counters.BusExceptionErr;
modbus_msg->ByteCnt = 4;
break;
case 0x000E: // Return Server Message Count
modbus_msg->DATA[0] = sub_function;
modbus_msg->DATA[1] = MB_DIAG.Counters.SlaveMessage;
modbus_msg->ByteCnt = 4;
break;
case 0x000F: // Return Slave No Response Count
modbus_msg->DATA[0] = sub_function;
modbus_msg->DATA[1] = MB_DIAG.Counters.SlaveNoResponse;
modbus_msg->ByteCnt = 4;
break;
case 0x0010: // Return Slave NAK Count
modbus_msg->DATA[0] = sub_function;
modbus_msg->DATA[1] = MB_DIAG.Counters.SlaveNAK;
modbus_msg->ByteCnt = 4;
break;
case 0x0011: // Return Slave Busy Count
modbus_msg->DATA[0] = sub_function;
modbus_msg->DATA[1] = MB_DIAG.Counters.SlaveBusy;
modbus_msg->ByteCnt = 4;
break;
case 0x0012: // Return Bus Character Overrun Count
modbus_msg->DATA[0] = sub_function;
modbus_msg->DATA[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->DATA[0] = sub_function;
modbus_msg->DATA[1] = 0;
modbus_msg->ByteCnt = 4;
break;
default:
modbus_msg->Func_Code |= ERR_VALUES_START;
modbus_msg->Except_Code = 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;
}

View File

@@ -21,6 +21,8 @@
#include "modbus_inputregs.h"
/**
* @brief Proccess command Read Holding Registers (03 - 0x03).
* @param modbus_msg Указатель на структуру собщения modbus.

View File

@@ -9,7 +9,6 @@
Копирование данных из структур устройства в буфер ответа
- Поддержка знаковых и беззнаковых значений
******************************************************************************/
#include "modbus_inputregs.h"

View File

@@ -23,6 +23,7 @@
- RS_TIM_Handler() в TIMx_IRQHandler вместо HAL_TIM_IRQHandler()
******************************************************************************/
#include "rs_message.h"
#include "modbus_diag.h"
uint8_t RS_Buffer[MSG_SIZE_MAX]; // uart buffer
@@ -356,20 +357,9 @@ void RS_UART_Handler(RS_HandleTypeDef *hRS)
// Парсим наше сообщение
RS_StatusTypeDef parse_res = RS_Parse_Message(hRS, hRS->pMessagePtr, hRS->pBufferPtr);
// Проверяем адрес Modbus перед обработкой
if(hRS->pMessagePtr->MbAddr != hRS->ID)
{
// Чужое сообщение - игнорируем и начинаем новый прием
RS_Abort(hRS, ABORT_RX);
RS_Handle_Receive_Start(hRS, hRS->pMessagePtr);
return;
}
// Если сообещине принято корректно - отвечаем на него
if(parse_res != RS_SKIP)
if(parse_res == RS_OK)
{
if(hRS->htim)
{
@@ -425,6 +415,10 @@ void RS_UART_Handler(RS_HandleTypeDef *hRS)
//----------------ERRORS HANDLER----------------
else
{
if (hRS->huart->ErrorCode & HAL_UART_ERROR_ORE)
{
MB_Diagnostics_CharacterOverrunCnt(); // <-- Обнаружено переполнение
}
//TrackerCnt_Err(hRS->rs_err);
/* de-init uart transfer */
RS_Abort(hRS, ABORT_RS);