release 0.2
Добавлен модуль диагностически модбас (функция 0x08) + мелкие кореркции
This commit is contained in:
@@ -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
|
||||
* @}
|
||||
*/
|
||||
|
||||
@@ -81,7 +81,7 @@ typedef enum
|
||||
/**
|
||||
* @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS Modbus Data Access
|
||||
* @ingroup MODBUS_FUNCTIONS
|
||||
* @brief Функции для доступа к данным модбас (коилы)
|
||||
* @brief Функции для доступа к данным модбас
|
||||
@{
|
||||
*/
|
||||
|
||||
|
||||
@@ -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
107
Inc/modbus_diag.h
Normal 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
|
||||
* @}
|
||||
*/
|
||||
@@ -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
|
||||
```
|
||||
|
||||
|
||||
173
Src/modbus.c
173
Src/modbus.c
@@ -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 Указатель на структуру сообщения.
|
||||
(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,11 +146,14 @@ 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
|
||||
{
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
293
Src/modbus_diag.c
Normal 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;
|
||||
}
|
||||
@@ -21,6 +21,8 @@
|
||||
#include "modbus_inputregs.h"
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Proccess command Read Holding Registers (03 - 0x03).
|
||||
* @param modbus_msg Указатель на структуру собщения modbus.
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
Копирование данных из структур устройства в буфер ответа
|
||||
- Поддержка знаковых и беззнаковых значений
|
||||
******************************************************************************/
|
||||
|
||||
#include "modbus_inputregs.h"
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -357,19 +358,8 @@ 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);
|
||||
|
||||
Reference in New Issue
Block a user