Compare commits
5 Commits
release
...
bare_modbu
| Author | SHA1 | Date | |
|---|---|---|---|
| 98e9e22752 | |||
|
|
c5c265ba6c | ||
|
|
b530a60de2 | ||
|
|
5c70316df7 | ||
|
|
fbc424e507 |
29
Doc/Doxyfile
29
Doc/Doxyfile
@@ -42,19 +42,19 @@ DOXYFILE_ENCODING = UTF-8
|
|||||||
# title of most generated pages and in a few other places.
|
# title of most generated pages and in a few other places.
|
||||||
# The default value is: My Project.
|
# The default value is: My Project.
|
||||||
|
|
||||||
PROJECT_NAME = MyLibs
|
PROJECT_NAME = Modbus
|
||||||
|
|
||||||
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
|
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
|
||||||
# could be handy for archiving the generated documentation or if some version
|
# could be handy for archiving the generated documentation or if some version
|
||||||
# control system is used.
|
# control system is used.
|
||||||
|
|
||||||
PROJECT_NUMBER = 1.0
|
PROJECT_NUMBER = 0.3
|
||||||
|
|
||||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||||
# for a project that appears at the top of each page and should give viewers a
|
# for a project that appears at the top of each page and should give viewers a
|
||||||
# quick idea about the purpose of the project. Keep the description short.
|
# quick idea about the purpose of the project. Keep the description short.
|
||||||
|
|
||||||
PROJECT_BRIEF = "Расширенные библиотеки для STM32"
|
PROJECT_BRIEF = "Библиотека Modbus для STM"
|
||||||
|
|
||||||
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
|
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
|
||||||
# in the documentation. The maximum height of the logo should not exceed 55
|
# in the documentation. The maximum height of the logo should not exceed 55
|
||||||
@@ -273,7 +273,7 @@ SEPARATE_MEMBER_PAGES = NO
|
|||||||
# uses this value to replace tabs by spaces in code fragments.
|
# uses this value to replace tabs by spaces in code fragments.
|
||||||
# Minimum value: 1, maximum value: 16, default value: 4.
|
# Minimum value: 1, maximum value: 16, default value: 4.
|
||||||
|
|
||||||
TAB_SIZE = 4
|
TAB_SIZE = 2
|
||||||
|
|
||||||
# This tag can be used to specify a number of aliases that act as commands in
|
# This tag can be used to specify a number of aliases that act as commands in
|
||||||
# the documentation. An alias has the form:
|
# the documentation. An alias has the form:
|
||||||
@@ -991,7 +991,9 @@ WARN_LOGFILE =
|
|||||||
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
||||||
# Note: If this tag is empty the current directory is searched.
|
# Note: If this tag is empty the current directory is searched.
|
||||||
|
|
||||||
INPUT = E:\.WORK\STM32\STM32_Modbus\Modbus
|
INPUT = ../ \
|
||||||
|
../Modbus/Inc \
|
||||||
|
../Modbus/Src
|
||||||
|
|
||||||
# This tag can be used to specify the character encoding of the source files
|
# This tag can be used to specify the character encoding of the source files
|
||||||
# that Doxygen parses. Internally Doxygen uses the UTF-8 encoding. Doxygen uses
|
# that Doxygen parses. Internally Doxygen uses the UTF-8 encoding. Doxygen uses
|
||||||
@@ -1086,7 +1088,7 @@ FILE_PATTERNS = *.c \
|
|||||||
# be searched for input files as well.
|
# be searched for input files as well.
|
||||||
# The default value is: NO.
|
# The default value is: NO.
|
||||||
|
|
||||||
RECURSIVE = YES
|
RECURSIVE = NO
|
||||||
|
|
||||||
# The EXCLUDE tag can be used to specify files and/or directories that should be
|
# The EXCLUDE tag can be used to specify files and/or directories that should be
|
||||||
# excluded from the INPUT source files. This way you can easily exclude a
|
# excluded from the INPUT source files. This way you can easily exclude a
|
||||||
@@ -1206,7 +1208,7 @@ FILTER_SOURCE_PATTERNS =
|
|||||||
# (index.html). This can be useful if you have a project on for instance GitHub
|
# (index.html). This can be useful if you have a project on for instance GitHub
|
||||||
# and want to reuse the introduction page also for the Doxygen output.
|
# and want to reuse the introduction page also for the Doxygen output.
|
||||||
|
|
||||||
USE_MDFILE_AS_MAINPAGE =
|
USE_MDFILE_AS_MAINPAGE = ..\README.md
|
||||||
|
|
||||||
# If the IMPLICIT_DIR_DOCS tag is set to YES, any README.md file found in sub-
|
# If the IMPLICIT_DIR_DOCS tag is set to YES, any README.md file found in sub-
|
||||||
# directories of the project's root, is used as the documentation for that sub-
|
# directories of the project's root, is used as the documentation for that sub-
|
||||||
@@ -1215,7 +1217,7 @@ USE_MDFILE_AS_MAINPAGE =
|
|||||||
# command in order to be used as directory documentation.
|
# command in order to be used as directory documentation.
|
||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
|
|
||||||
IMPLICIT_DIR_DOCS = YES
|
IMPLICIT_DIR_DOCS = NO
|
||||||
|
|
||||||
# The Fortran standard specifies that for fixed formatted Fortran code all
|
# The Fortran standard specifies that for fixed formatted Fortran code all
|
||||||
# characters from position 72 are to be considered as comment. A common
|
# characters from position 72 are to be considered as comment. A common
|
||||||
@@ -2498,7 +2500,7 @@ MACRO_EXPANSION = YES
|
|||||||
# The default value is: NO.
|
# The default value is: NO.
|
||||||
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
||||||
|
|
||||||
EXPAND_ONLY_PREDEF = NO
|
EXPAND_ONLY_PREDEF = YES
|
||||||
|
|
||||||
# If the SEARCH_INCLUDES tag is set to YES, the include files in the
|
# If the SEARCH_INCLUDES tag is set to YES, the include files in the
|
||||||
# INCLUDE_PATH will be searched if a #include is found.
|
# INCLUDE_PATH will be searched if a #include is found.
|
||||||
@@ -2513,7 +2515,8 @@ SEARCH_INCLUDES = YES
|
|||||||
# RECURSIVE has no effect here.
|
# RECURSIVE has no effect here.
|
||||||
# This tag requires that the tag SEARCH_INCLUDES is set to YES.
|
# This tag requires that the tag SEARCH_INCLUDES is set to YES.
|
||||||
|
|
||||||
INCLUDE_PATH =
|
INCLUDE_PATH = ../Modbus/Inc \
|
||||||
|
../
|
||||||
|
|
||||||
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
|
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
|
||||||
# patterns (like *.h and *.hpp) to filter out the header-files in the
|
# patterns (like *.h and *.hpp) to filter out the header-files in the
|
||||||
@@ -2531,11 +2534,7 @@ INCLUDE_FILE_PATTERNS =
|
|||||||
# recursively expanded use the := operator instead of the = operator.
|
# recursively expanded use the := operator instead of the = operator.
|
||||||
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
||||||
|
|
||||||
PREDEFINED = RTT_TRACE_ENABLE \
|
PREDEFINED =
|
||||||
GPIO_TRACE_ENABLE \
|
|
||||||
SERIAL_TRACE_ENABLE \
|
|
||||||
HAL_MODULE_ENABLED \
|
|
||||||
TRACKERS_ENABLE
|
|
||||||
|
|
||||||
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
|
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
|
||||||
# tag can be used to specify a list of macro names that should be expanded. The
|
# tag can be used to specify a list of macro names that should be expanded. The
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
******************************************************************************
|
******************************************************************************
|
||||||
@addtogroup MODBUS Modbus tools
|
@addtogroup MODBUS Modbus tools
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
@addtogroup MODBUS_FUNCTIONS Modbus library funtions
|
@addtogroup MODBUS_FUNCTIONS Main API for Modbus Library
|
||||||
@ingroup MODBUS
|
@ingroup MODBUS
|
||||||
@{
|
@{
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
@@ -14,41 +14,51 @@
|
|||||||
Подключает все необходимые модули:
|
Подключает все необходимые модули:
|
||||||
|
|
||||||
|
|
||||||
@section Инструкция по подключению
|
@section init Инструкция по подключению
|
||||||
Для корректной работы надо:
|
Для корректной работы надо:
|
||||||
- Подключить обработчики RS_UART_Handler(), RS_TIM_Handler(), в соответствубщие
|
- Подключить обработчики RS_UART_Handler(), RS_TIM_Handler(), в соответствубщие
|
||||||
низкоуровневые прерывания UART_IRQHandler, TIM_IRQHandler. Вместо HAL'овского обработчика
|
низкоуровневые прерывания UART_IRQHandler, TIM_IRQHandler вместо HAL'овского обработчика
|
||||||
|
|
||||||
В modbus_config.h настроить дефайны для нужной работы UART
|
- В modbus_config.h настроить дефайны для нужной работы UART
|
||||||
|
|
||||||
- Инициализировать хендл мобдас. По умолчанию глобально создается hmodbus1, но можно сделать свой
|
- Инициализировать хендл мобдас. По умолчанию глобально создается hmodbus1
|
||||||
После для запуска Modbus:
|
- После для запуска Modbus:
|
||||||
@verbatim
|
@verbatim
|
||||||
//----------------Прием модбас----------------//
|
//----------------Слейв модбас----------------//
|
||||||
#include "modbus.h"
|
#include "modbus.h"
|
||||||
|
|
||||||
MODBUS_SetupHardware(&hmodbus1, &huart1, &htim3);
|
MODBUS_FirstInit(&hmodbus1, &huart1, &htim3);
|
||||||
MODBUS_SlaveStart(&hmodbus1, NULL);
|
MODBUS_Config(&hmodbus1, 1, 1000, MODBUS_MODE_SLAVE);
|
||||||
// или если нужно переключится на другой
|
MODBUS_SlaveStart(&hmodbus1, NULL);
|
||||||
@endverbatim
|
@endverbatim
|
||||||
|
@verbatim
|
||||||
|
//----------------Мастер модбас----------------//
|
||||||
|
#include "modbus.h"
|
||||||
|
|
||||||
|
MODBUS_FirstInit(&hmodbus1, &huart1, &htim3);
|
||||||
|
MODBUS_Config(&hmodbus1, 0, 1000, MODBUS_MODE_MASTER); // - если нужны другие настройки, не из modbus_config.h
|
||||||
|
// Запрос на 1 ID, считать холдинг регистры с 0 адреса 10 штук
|
||||||
|
RS_MsgTypeDef msg = MB_REQUEST_READ_HOLDING_REGS(1, 0, 10);
|
||||||
|
MODBUS_MasterRequest(&hmodbus1, &msg, &callback_func);
|
||||||
|
|
||||||
|
void callback_func(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
|
||||||
|
{
|
||||||
|
// modbus_msg содержит ответ от устройства
|
||||||
|
}
|
||||||
|
@endverbatim
|
||||||
|
|
||||||
|
|
||||||
@section Подключаемые модули:
|
@section Подключаемые модули:
|
||||||
|
- rs_message.h - работа с uart
|
||||||
- modbus_core.h - базовые определения
|
- modbus_core.h - базовые определения
|
||||||
- modbus_coils.h - работа с дискретными выходами
|
- modbus_coils.h - работа с дискретными выходами
|
||||||
- modbus_holdregs.h - работа с регистрами хранения
|
- modbus_holdregs.h - работа с регистрами хранения
|
||||||
- modbus_inputregs.h - работа с входными регистрами
|
- modbus_inputregs.h - работа с входными регистрами
|
||||||
- modbus_devid.h - идентификация устройства
|
- modbus_devid.h - идентификация устройства
|
||||||
- __crc_algs.h - алгоритмы CRC
|
- modbus_diag.h - диагностика modbus
|
||||||
|
|
||||||
@section Использование в проекте:
|
|
||||||
1. Настроить modbus_config.h под устройство
|
|
||||||
2. Определить структуры данных в modbus_data.h
|
|
||||||
3. Подключить этот файл в rs_message.h
|
|
||||||
4. Вызвать MODBUS_FirstInit() и RS_Receive_IT()
|
|
||||||
|
|
||||||
|
|
||||||
@section Структура данных Modbus
|
@section Структура данных Modbus
|
||||||
|
|
||||||
#### Holding/Input Registers:
|
#### Holding/Input Registers:
|
||||||
- Регистры — 16-битные слова. Доступ к регистрам осуществляется через указатель.
|
- Регистры — 16-битные слова. Доступ к регистрам осуществляется через указатель.
|
||||||
@@ -62,12 +72,14 @@ MODBUS_SlaveStart(&hmodbus1, NULL);
|
|||||||
#ifndef __MODBUS_H_
|
#ifndef __MODBUS_H_
|
||||||
#define __MODBUS_H_
|
#define __MODBUS_H_
|
||||||
|
|
||||||
#include "__crc_algs.h"
|
|
||||||
#include "rs_message.h"
|
#include "rs_message.h"
|
||||||
|
#include "modbus_master.h"
|
||||||
|
#include "modbus_slave.h"
|
||||||
#include "modbus_coils.h"
|
#include "modbus_coils.h"
|
||||||
#include "modbus_holdregs.h"
|
#include "modbus_holdregs.h"
|
||||||
#include "modbus_inputregs.h"
|
#include "modbus_inputregs.h"
|
||||||
#include "modbus_devid.h"
|
#include "modbus_devid.h"
|
||||||
|
#include "modbus_diag.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -76,20 +88,16 @@ MODBUS_SlaveStart(&hmodbus1, NULL);
|
|||||||
|
|
||||||
|
|
||||||
//----------------FUNCTIONS FOR USER----------------
|
//----------------FUNCTIONS FOR USER----------------
|
||||||
/**
|
|
||||||
* @addtogroup MODBUS_INIT_FUNCTIONS Functions for Init
|
|
||||||
* @ingroup MODBUS_FUNCTIONS
|
|
||||||
* @brief Функции для инициализации
|
|
||||||
@{
|
|
||||||
*/
|
|
||||||
/* Инициализация периферии модбас. */
|
|
||||||
void MODBUS_SetupHardware(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim);
|
|
||||||
/* Программная конфигурация модбас. */
|
|
||||||
void MODBUS_Config(RS_HandleTypeDef *hmodbus, uint8_t ID, uint16_t Timeout, uint8_t master);
|
|
||||||
|
|
||||||
/** MODBUS_INIT_FUNCTIONS
|
/* Инициализация периферии модбас. */
|
||||||
* @}
|
HAL_StatusTypeDef MODBUS_FirstInit(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim);
|
||||||
*/
|
/* Программная конфигурация модбас. */
|
||||||
|
HAL_StatusTypeDef MODBUS_Config(RS_HandleTypeDef *hmodbus, uint8_t ID, uint16_t Timeout, uint8_t master);
|
||||||
|
/* Запуск слейв устройства */
|
||||||
|
HAL_StatusTypeDef MODBUS_SlaveStart(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg);
|
||||||
|
/* Реквест мастера модбас */
|
||||||
|
HAL_StatusTypeDef MODBUS_MasterRequest(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, void (*pClbk)(RS_HandleTypeDef*, RS_MsgTypeDef*));
|
||||||
|
|
||||||
|
|
||||||
//---------PROCESS MODBUS COMMAND FUNCTIONS---------
|
//---------PROCESS MODBUS COMMAND FUNCTIONS---------
|
||||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
******************************************************************************
|
******************************************************************************
|
||||||
@addtogroup MODBUS_COILS Coils Tools
|
@addtogroup MODBUS_COILS Coils Tools
|
||||||
@ingroup MODBUS_INTERNAL
|
@ingroup MODBUS_INTERNAL
|
||||||
@{
|
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* @details
|
* @details
|
||||||
Модуль предоставляет функции и макросы для работы с битовыми данными:
|
Модуль предоставляет функции и макросы для работы с битовыми данными:
|
||||||
@@ -14,11 +13,11 @@
|
|||||||
- Запись множественных coils (0x0F) - распаковка байтов в биты
|
- Запись множественных coils (0x0F) - распаковка байтов в биты
|
||||||
- Макросы для локального доступа к coils
|
- Макросы для локального доступа к coils
|
||||||
|
|
||||||
@section Организация битовых данных:
|
@section Организация битовых данных:
|
||||||
Coils упакованы в 16-битные слова для эффективного использования памяти.
|
Coils упакованы в 16-битные слова для эффективного использования памяти.
|
||||||
Биты нумеруются от младшего к старшему внутри каждого слова.
|
Биты нумеруются от младшего к старшему внутри каждого слова.
|
||||||
|
|
||||||
@section Адресация:
|
@section Адресация:
|
||||||
- Глобальная - абсолютный адрес в пространстве Modbus
|
- Глобальная - абсолютный адрес в пространстве Modbus
|
||||||
- Локальная - относительный адрес внутри массива coils
|
- Локальная - относительный адрес внутри массива coils
|
||||||
- Макросы автоматически вычисляют смещения и маски
|
- Макросы автоматически вычисляют смещения и маски
|
||||||
@@ -31,24 +30,24 @@ Coils упакованы в 16-битные слова для эффективн
|
|||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
////////////////////---MODBUS FUNCTION DEFINES---////////////////////
|
////////////////////---MODBUS FUNCTION DEFINES---////////////////////
|
||||||
|
|
||||||
/** @brief Structure for coils operation */
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
SET_COIL,
|
|
||||||
RESET_COIL,
|
|
||||||
TOOGLE_COIL,
|
|
||||||
}MB_CoilsOpTypeDef;
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup MODBUS_COILS
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Macros to set pointer to a certain register that contains certain coil
|
* @brief Макрос для установки указателя на регистр, содержащий запрашиваемый коил
|
||||||
* @param _parr_ - массив коилов.
|
* @param _parr_ - массив коилов.
|
||||||
* @param _coil_ - Номер коила от начала массива _arr_.
|
* @param _coil_ - Номер коила от начала массива _arr_.
|
||||||
* @note Используется вместе с @ref MB_Set_Coil_Mask
|
* @note Используется вместе с @ref MB_Set_Coil_Mask
|
||||||
@verbatim Пояснение выражений
|
@verbatim Пояснение выражений
|
||||||
(_coil_/16) - get index (address shift) of register that contain certain coil
|
- (_coil_/16) - индекс регистра, в котором содержится коил по адресу _coil_
|
||||||
Visual explanation: 30th coil in coils registers array
|
|
||||||
|
Визуальный пример: 30 коил будет в 30/16 = 1 регистре (индексация с 0)
|
||||||
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx
|
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx
|
||||||
|register[0]----| |register[1]----|
|
|register[0]----| |register[1]----|
|
||||||
|skip this------| |get this-------|
|
|skip this------| |get this-------|
|
||||||
@@ -57,15 +56,17 @@ typedef enum
|
|||||||
*/
|
*/
|
||||||
#define MB_Set_Coil_Reg_Ptr(_parr_, _coil_) ((uint16_t *)(_parr_)+((_coil_)/16))
|
#define MB_Set_Coil_Reg_Ptr(_parr_, _coil_) ((uint16_t *)(_parr_)+((_coil_)/16))
|
||||||
/**
|
/**
|
||||||
* @brief Macros to set mask to a certain bit in coils register
|
* @brief Макрос для установки маски, чтобы выделить запрашиваемый коил из регистра
|
||||||
* @param _coil_ - Номер коила от начала массива _arr_.
|
* @param _coil_ - Номер коила от начала массива _arr_.
|
||||||
* @note Используется вместе с @ref MB_Set_Coil_Reg_Ptr
|
* @note Используется вместе с @ref MB_Set_Coil_Reg_Ptr
|
||||||
@verbatim Пояснение выражений
|
@verbatim Пояснение выражений
|
||||||
(16*(_coil_/16) - how many coils we need to skip. e.g. (16*30/16) - skip 16 coils from first register
|
- (16*(_coil_/16) - сколько коилов нужно пропустить. прим. (16*30/16) - первые 16 коилов находятся вне регистра
|
||||||
_coil_-(16*(_coil_/16)) - shift to certain coil in certain register
|
- _coil_-(16*(_coil_/16)) - сдвинуть бит на место запрашиваемого коила в регистре
|
||||||
e.g. Coil(30) gets in register[1] (30/16 = 1) coil №14 (30 - (16*30/16) = 30 - 16 = 14)
|
|
||||||
|
|
||||||
Visual explanation: 30th coil in coils registers array
|
Визуальный пример: 30 коил будет регистре[1], на 14 бите:
|
||||||
|
register = 30/16 = 1
|
||||||
|
bit = 30 - (16*30/16) = 30 - 16 = 14
|
||||||
|
|
||||||
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx
|
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx
|
||||||
|register[0]----| |register[1]----|
|
|register[0]----| |register[1]----|
|
||||||
|skip this------| |get this-------|
|
|skip this------| |get this-------|
|
||||||
@@ -74,55 +75,104 @@ typedef enum
|
|||||||
*/
|
*/
|
||||||
#define MB_Set_Coil_Mask(_coil_) (1 << ( _coil_ - (16*((_coil_)/16)) ))
|
#define MB_Set_Coil_Mask(_coil_) (1 << ( _coil_ - (16*((_coil_)/16)) ))
|
||||||
|
|
||||||
|
/** MODBUS_COILS
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||||
|
|
||||||
/**
|
|
||||||
* @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS Modbus Data Access
|
/**
|
||||||
* @ingroup MODBUS_FUNCTIONS
|
* @addtogroup MODBUS_REQ_COILS_API API for Coils
|
||||||
* @brief Функции для доступа к данным модбас (коилы)
|
* @ingroup MODBUS_REQUEST_MSG
|
||||||
@{
|
* @brief API для чтения coils из ответа в режиме мастер
|
||||||
*/
|
* @details Примеры использования:
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* // Пример: Запросили 10 coils с адреса 20, хотим узнать состояние coil 25
|
||||||
|
* int coil_state;
|
||||||
|
* if(MB_RespGet_CoilState(&MODBUS_MSG, 25, &coil_state))
|
||||||
|
* {
|
||||||
|
* printf("Coil 25 state: %s\n", coil_state ? "ON" : "OFF");
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* // Пример: Получить состояние всех запрошенных coils
|
||||||
|
* for(int addr = MODBUS_MSG.Addr; addr < MODBUS_MSG.Addr + MODBUS_MSG.Qnt; addr++)
|
||||||
|
* {
|
||||||
|
* int state;
|
||||||
|
* if(MB_RespGet_CoilState(&MODBUS_MSG, addr, &state))
|
||||||
|
* {
|
||||||
|
* printf("Coil %d: %s\n", addr, state ? "ON" : "OFF");
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* @endcode
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
int MB_RespGet_CoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coil_state);
|
||||||
|
|
||||||
|
/** MODBUS_REQ_COILS_API
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS API for Data Access
|
||||||
|
* @ingroup MODBUS_FUNCTIONS
|
||||||
|
* @brief Функции для доступа к данным модбас
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @brief Structure for coils operation */
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
SET_COIL,
|
||||||
|
RESET_COIL,
|
||||||
|
TOOGLE_COIL,
|
||||||
|
}MB_CoilsOpTypeDef;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read Coil at its local address.
|
* @brief Считать коил по локальному адресу.
|
||||||
* @param _parr_ - массив коилов.
|
* @param _parr_ - массив коилов.
|
||||||
* @param _coil_ - Номер коила от начала массива _arr_.
|
* @param _coil_ - Номер коила от начала массива _arr_.
|
||||||
* @return uint16_t Возвращает запрошенный коил на 0м бите.
|
* @return uint16_t Возвращает запрошенный коил на 0м бите.
|
||||||
*
|
*
|
||||||
* @details Позволяет обратиться к коилу по адресу относительно _arr_.
|
* @details Позволяет обратиться к коилу по адресу относительно _arr_.
|
||||||
*/
|
*/
|
||||||
#define MB_Read_Coil_Local(_parr_, _coil_) (( *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) & MB_Set_Coil_Mask(_coil_) ) >> (_coil_))
|
#define MB_Coil_Read_Local(_parr_, _coil_) (( *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) & MB_Set_Coil_Mask(_coil_) ) >> (_coil_))
|
||||||
/**
|
/**
|
||||||
* @brief Set Coil at its local address.
|
* @brief Выставить коил по локальному адресу.
|
||||||
* @param _parr_ Указатель на массив коилов.
|
* @param _parr_ Указатель на массив коилов.
|
||||||
* @param _coil_ - Номер коила от начала массива _arr_.
|
* @param _coil_ - Номер коила от начала массива _arr_.
|
||||||
*
|
*
|
||||||
* @details Позволяет обратиться к коилу по адресу относительно _arr_.
|
* @details Позволяет обратиться к коилу по адресу относительно _arr_.
|
||||||
*/
|
*/
|
||||||
#define MB_Set_Coil_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) |= MB_Set_Coil_Mask(_coil_)
|
#define MB_Coil_Set_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) |= MB_Set_Coil_Mask(_coil_)
|
||||||
/**
|
/**
|
||||||
* @brief Reset Coil at its local address.
|
* @brief Сбросить коил по локальному адресу.
|
||||||
* @param _parr_ Указатель на массив коилов.
|
* @param _parr_ Указатель на массив коилов.
|
||||||
* @param _coil_ - Номер коила от начала массива _arr_.
|
* @param _coil_ - Номер коила от начала массива _arr_.
|
||||||
*
|
*
|
||||||
* @details Позволяет обратиться к коилу по адресу относительно _arr_.
|
* @details Позволяет обратиться к коилу по адресу относительно _arr_.
|
||||||
*/
|
*/
|
||||||
#define MB_Reset_Coil_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) &= ~(MB_Set_Coil_Mask(_coil_))
|
#define MB_Coil_Reset_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) &= ~(MB_Set_Coil_Mask(_coil_))
|
||||||
/**
|
/**
|
||||||
* @brief Set Coil at its local address.
|
* @brief Переключить состояние коила по локальному адресу.
|
||||||
* @param _parr_ Указатель на массив коилов.
|
* @param _parr_ Указатель на массив коилов.
|
||||||
* @param _coil_ - Номер коила от начала массива _arr_.
|
* @param _coil_ - Номер коила от начала массива _arr_.
|
||||||
*
|
*
|
||||||
* @details Позволяет обратиться к коилу по адресу относительно _arr_.
|
* @details Позволяет обратиться к коилу по адресу относительно _arr_.
|
||||||
*/
|
*/
|
||||||
#define MB_Toogle_Coil_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) ^= MB_Set_Coil_Mask(_coil_)
|
#define MB_Coil_Toogle_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) ^= MB_Set_Coil_Mask(_coil_)
|
||||||
|
|
||||||
/* Set or Reset Coil at its global address */
|
/* Выставить/сбросить коил по глобальному адресу */
|
||||||
MB_ExceptionTypeDef MB_Write_Coil_Global(uint16_t Addr, MB_CoilsOpTypeDef WriteVal);
|
MB_ExceptionTypeDef MB_Coil_Write_Global(uint16_t Addr, MB_CoilsOpTypeDef WriteVal);
|
||||||
/* Read Coil at its global address */
|
/* Считать коил по глобальному адресу */
|
||||||
uint16_t MB_Read_Coil_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception);
|
uint16_t MB_Coil_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception);
|
||||||
|
|
||||||
/** MODBUS_DATA_ACCESS_FUNCTIONS
|
/** MODBUS_DATA_ACCESS_FUNCTIONS
|
||||||
* @}
|
* @}
|
||||||
@@ -133,12 +183,12 @@ uint16_t MB_Read_Coil_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception);
|
|||||||
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
|
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
|
||||||
@{
|
@{
|
||||||
*/
|
*/
|
||||||
/* Proccess command Read Coils (01 - 0x01) */
|
/* Обработать функцию Read Coils (01 - 0x01) */
|
||||||
uint8_t MB_Proccess_Read_Coils(RS_MsgTypeDef *modbus_msg);
|
uint8_t MB_Process_Read_Coils(RS_MsgTypeDef *modbus_msg);
|
||||||
/* Proccess command Write Single Coils (05 - 0x05) */
|
/* Обработать функцию Write Single Coils (05 - 0x05) */
|
||||||
uint8_t MB_Proccess_Write_Single_Coil(RS_MsgTypeDef *modbus_msg);
|
uint8_t MB_Process_Write_Single_Coil(RS_MsgTypeDef *modbus_msg);
|
||||||
/* Proccess command Write Multiple Coils (15 - 0x0F) */
|
/* Обработать функцию Write Multiple Coils (15 - 0x0F) */
|
||||||
uint8_t MB_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg);
|
uint8_t MB_Process_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg);
|
||||||
|
|
||||||
/** MODBUS_CMD_PROCESS_FUNCTIONS
|
/** MODBUS_CMD_PROCESS_FUNCTIONS
|
||||||
* @}
|
* @}
|
||||||
|
|||||||
@@ -19,23 +19,36 @@
|
|||||||
#include "stm32f1xx_hal.h"
|
#include "stm32f1xx_hal.h"
|
||||||
|
|
||||||
// Общие параметры
|
// Общие параметры
|
||||||
#define MODBUS_DEVICE_ID 1 ///< девайс текущего устройства
|
#define MODBUS_DEVICE_ID 1 ///< Адрес устройства в сети Modbus
|
||||||
#define MODBUS_TIMEOUT 5000 ///< максимальнйы тайтаут MB в тиках таймера
|
#define MODBUS_TIMEOUT 5000 ///< Таймаут в тиках таймера
|
||||||
|
|
||||||
// Строковые идентификаторы устройства
|
// Строковые идентификаторы устройства
|
||||||
#define MODBUS_VENDOR_NAME "NIO-12"
|
#define MODBUS_VENDOR_NAME "NIO-12"
|
||||||
#define MODBUS_PRODUCT_CODE ""
|
#define MODBUS_PRODUCT_CODE ""
|
||||||
#define MODBUS_REVISION "Ver. 1.0"
|
#define MODBUS_REVISION ""
|
||||||
#define MODBUS_VENDOR_URL ""
|
#define MODBUS_VENDOR_URL ""
|
||||||
#define MODBUS_PRODUCT_NAME ""
|
#define MODBUS_PRODUCT_NAME ""
|
||||||
#define MODBUS_MODEL_NAME "STM32F103"
|
#define MODBUS_MODEL_NAME ""
|
||||||
#define MODBUS_USER_APPLICATION_NAME ""
|
#define MODBUS_USER_APPLICATION_NAME ""
|
||||||
#define MODBUS_NUMB_OF_USEROBJECTS 0
|
#define MODBUS_NUMB_OF_USEROBJECTS 0
|
||||||
|
|
||||||
// Периферия (опционально)
|
// Периферия (опционально)
|
||||||
#define mb_huart huart1 ///< Удобный дефайн для модбасовского uart
|
#define mb_huart huart1 ///< Удобный дефайн для модбасовского uart
|
||||||
#define mb_htim htim3 ///< Удобный дефайн для модбасовского таймера
|
#define mb_htim htim3 ///< Удобный дефайн для модбасовского таймера
|
||||||
///<
|
//#define RS_EnableReceive() ///< Функция изменения направления передачи на ПРИЕМ для RS-485
|
||||||
|
//#define RS_EnableTransmit() ///< Функция изменения направления передачи на ПЕРЕДАЧУ для RS-485
|
||||||
|
|
||||||
|
|
||||||
|
// Модули modbus
|
||||||
|
#define MODBUS_ENABLE_SLAVE ///< Включить обработку СЛЕЙВ режима
|
||||||
|
#define MODBUS_ENABLE_MASTER ///< Включить обработку МАСТЕР режима
|
||||||
|
|
||||||
|
#define MODBUS_ENABLE_COILS ///< Включить обработку коилов
|
||||||
|
#define MODBUS_ENABLE_HOLDINGS ///< Включить обработку регистров хранения
|
||||||
|
#define MODBUS_ENABLE_INPUTS ///< Включить обработку входных регистров
|
||||||
|
#define MODBUS_ENABLE_DEVICE_IDENTIFICATIONS ///< Включить обработку идентификаторы устройства
|
||||||
|
#define MODBUS_ENABLE_DIAGNOSTICS ///< Включить обработку диагностики модбас
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Поменять комманды 0x03 и 0x04 местами (для LabView терминалки от двигателей)
|
* @brief Поменять комманды 0x03 и 0x04 местами (для LabView терминалки от двигателей)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
Константы размеров полей
|
Константы размеров полей
|
||||||
Вспомогательные макросы
|
Вспомогательные макросы
|
||||||
|
|
||||||
@section Структура сообщения:
|
@section Структура сообщения:
|
||||||
[ADDR][FUNC][DATA...][CRC]
|
[ADDR][FUNC][DATA...][CRC]
|
||||||
- Адрес: 1 байт
|
- Адрес: 1 байт
|
||||||
- Функция: 1 байт
|
- Функция: 1 байт
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include "modbus_config.h"
|
#include "modbus_config.h"
|
||||||
#include "modbus_data.h"
|
#include "modbus_data.h"
|
||||||
|
#include "__crc_algs.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup MODBUS_MESSAGE_DEFINES Modbus Message Tools
|
* @addtogroup MODBUS_MESSAGE_DEFINES Modbus Message Tools
|
||||||
@@ -93,8 +94,8 @@ typedef enum //MB_FunctonTypeDef
|
|||||||
MB_W_COILS = 0x0F, ///< Запись нескольких битовых ячеек
|
MB_W_COILS = 0x0F, ///< Запись нескольких битовых ячеек
|
||||||
MB_W_HOLD_REGS = 0x10, ///< Запись нескольких регистров
|
MB_W_HOLD_REGS = 0x10, ///< Запись нескольких регистров
|
||||||
|
|
||||||
MB_R_DIAGNOSTIC = 0x08, ///< Чтение диагностической информации устройства
|
MB_R_DIAGNOSTIC = 0x08, ///< Чтение диагностической информации устройства
|
||||||
MB_R_DEVICE_INFO = 0x2B, ///< Чтение информации об устройстве
|
MB_R_DEVICE_INFO = 0x2B, ///< Чтение информации об устройстве
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
// error reading
|
// error reading
|
||||||
@@ -116,39 +117,39 @@ typedef enum //MB_FunctonTypeDef
|
|||||||
/** @brief Structure for MEI func codes */
|
/** @brief Structure for MEI func codes */
|
||||||
typedef enum //MB_FunctonTypeDef
|
typedef enum //MB_FunctonTypeDef
|
||||||
{
|
{
|
||||||
MEI_DEVICE_IDENTIFICATION = 0x0E,
|
MEI_DEVICE_IDENTIFICATIONS = 0x0E,
|
||||||
}MB_MEITypeDef;
|
}MB_MEITypeDef;
|
||||||
|
|
||||||
/** @brief Structure for comformity */
|
/** @brief Structure for comformity */
|
||||||
typedef enum //MB_FunctonTypeDef
|
typedef enum //MB_FunctonTypeDef
|
||||||
{
|
{
|
||||||
MB_BASIC_IDENTIFICATION = 0x01, /*!< @brief Basic Device Identification.
|
MB_BASIC_IDENTIFICATIONS = 0x01, /*!< @brief Basic Device Identifications.
|
||||||
@details All objects of this category are mandatory:
|
@details All objects of this category are mandatory:
|
||||||
VendorName,Product code, and revision number */
|
VendorName,Product code, and revision number */
|
||||||
|
|
||||||
MB_REGULAR_IDENTIFICATION = 0x02, /*!< @brief Regular Device Identification.
|
MB_REGULAR_IDENTIFICATIONS = 0x02, /*!< @brief Regular Device Identifications.
|
||||||
@details The device provides additional and optional
|
@details The device provides additional and optional
|
||||||
identification and description data objects */
|
identifications and description data objects */
|
||||||
|
|
||||||
MB_EXTENDED_IDENTIFICATION = 0x03, /*!< @brief Extended Device Identification.
|
MB_EXTENDED_IDENTIFICATIONS = 0x03, /*!< @brief Extended Device Identifications.
|
||||||
@details The device provides additional and optional
|
@details The device provides additional and optional
|
||||||
identification and description private data about the physical
|
identifications and description private data about the physical
|
||||||
device itself. All of these data are device dependent. */
|
device itself. All of these data are device dependent. */
|
||||||
|
|
||||||
MB_SPEDIFIC_IDENTIFICATION = 0x04, /*!< @brief Specific Device Identification.
|
MB_SPEDIFIC_IDENTIFICATIONS = 0x04, /*!< @brief Specific Device Identifications.
|
||||||
@details The device provides one specific identification object. */
|
@details The device provides one specific identifications object. */
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
MB_ERR_BASIC_IDENTIFICATION = MB_BASIC_IDENTIFICATION + ERR_VALUES_START,
|
MB_ERR_BASIC_IDENTIFICATIONS = MB_BASIC_IDENTIFICATIONS + ERR_VALUES_START,
|
||||||
MB_ERR_REGULAR_IDENTIFICATION = MB_REGULAR_IDENTIFICATION + ERR_VALUES_START,
|
MB_ERR_REGULAR_IDENTIFICATIONS = MB_REGULAR_IDENTIFICATIONS + ERR_VALUES_START,
|
||||||
MB_ERR_EXTENDED_IDENTIFICATION = MB_REGULAR_IDENTIFICATION + ERR_VALUES_START,
|
MB_ERR_EXTENDED_IDENTIFICATIONS = MB_REGULAR_IDENTIFICATIONS + ERR_VALUES_START,
|
||||||
MB_ERR_SPEDIFIC_IDENTIFICATION = MB_REGULAR_IDENTIFICATION + ERR_VALUES_START,
|
MB_ERR_SPEDIFIC_IDENTIFICATIONS = MB_REGULAR_IDENTIFICATIONS + ERR_VALUES_START,
|
||||||
}MB_ConformityTypeDef;
|
}MB_ConformityTypeDef;
|
||||||
|
|
||||||
/** @brief Structure for decive identification message type */
|
/** @brief Structure for decive identifications message type */
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
MB_MEITypeDef MEI_Type; ///< MEI Type assigned number for Device Identification Interface
|
MB_MEITypeDef MEI_Type; ///< MEI Type assigned number for Device Identifications Interface
|
||||||
MB_ConformityTypeDef ReadDevId;
|
MB_ConformityTypeDef ReadDevId;
|
||||||
MB_ConformityTypeDef Conformity;
|
MB_ConformityTypeDef Conformity;
|
||||||
uint8_t MoreFollows;
|
uint8_t MoreFollows;
|
||||||
@@ -162,7 +163,7 @@ typedef struct // RS_MsgTypeDef
|
|||||||
{
|
{
|
||||||
uint8_t MbAddr; ///< Modbus Slave Address
|
uint8_t MbAddr; ///< Modbus Slave Address
|
||||||
MB_FunctonTypeDef Func_Code; ///< Modbus Function Code
|
MB_FunctonTypeDef Func_Code; ///< Modbus Function Code
|
||||||
MB_DevIdMsgTypeDef DevId; ///< Read Device Identification Header struct
|
MB_DevIdMsgTypeDef DevId; ///< Read Device Identifications Header struct
|
||||||
uint16_t Addr; ///< Modbus Address of data
|
uint16_t Addr; ///< Modbus Address of data
|
||||||
uint16_t Qnt; ///< Quantity of modbus data
|
uint16_t Qnt; ///< Quantity of modbus data
|
||||||
uint8_t ByteCnt; ///< Quantity of bytes of data in message to transmit/receive
|
uint8_t ByteCnt; ///< Quantity of bytes of data in message to transmit/receive
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
- Input Registers (R/O) - входные регистры
|
- Input Registers (R/O) - входные регистры
|
||||||
- Coils (R/W) - дискретные выходы
|
- Coils (R/W) - дискретные выходы
|
||||||
|
|
||||||
@section Базовая настройка под устройство:
|
@section Базовая настройка под устройство:
|
||||||
1. Настроить диапазоны адресов
|
1. Настроить диапазоны адресов
|
||||||
- @ref R_INPUT_ADDR и @ref R_INPUT_QNT для входных регистров
|
- @ref R_INPUT_ADDR и @ref R_INPUT_QNT для входных регистров
|
||||||
- @ref R_HOLDING_ADDR и @ref R_HOLDING_QNT для регистров хранения
|
- @ref R_HOLDING_ADDR и @ref R_HOLDING_QNT для регистров хранения
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
- @ref MB_DataCoilsTypeDef
|
- @ref MB_DataCoilsTypeDef
|
||||||
|
|
||||||
|
|
||||||
@section Расширенная настройка под устройство:
|
@section Расширенная настройка под устройство:
|
||||||
1. Добавить новый массив с нужными данными.
|
1. Добавить новый массив с нужными данными.
|
||||||
2. Добавить дефайны для определения его начального адреса и количества элементов
|
2. Добавить дефайны для определения его начального адреса и количества элементов
|
||||||
3. Добавить проверку адресов в MB_DefineRegistersAddress/MB_DefineCoilsAddress.
|
3. Добавить проверку адресов в MB_DefineRegistersAddress/MB_DefineCoilsAddress.
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
/**
|
/**
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* @file modbus_devid.h
|
* @file modbus_devid.h
|
||||||
* @brief Идентификация устройства Modbus
|
* @brief Идентификаторы устройства Modbus
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
@addtogroup MODBUS_DEVID Device Identificators Tools
|
@addtogroup MODBUS_DEVID Device Identifications Tools
|
||||||
@ingroup MODBUS_INTERNAL
|
@ingroup MODBUS_INTERNAL
|
||||||
@{
|
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* @details
|
* @details
|
||||||
Модуль реализации функции Read Device Identification (0x2B):
|
Модуль реализации функции Read Device Identifications (0x2B):
|
||||||
- Базовая идентификация (Vendor, Product, Revision)
|
- Базовая идентификация (Vendor, Product, Revision)
|
||||||
- Расширенная идентификация (URL, Model, User fields)
|
- Расширенная идентификация (URL, Model, User fields)
|
||||||
- Поддержка потоковой передачи больших объектов
|
- Поддержка потоковой передачи больших объектов
|
||||||
|
|
||||||
@section Объекты идентификации:
|
@section Объекты идентификации:
|
||||||
- VendorName, ProductCode, Revision - обязательные
|
- VendorName, ProductCode, Revision - обязательные
|
||||||
- VendorUrl, ProductName, ModelName - опциональные
|
- VendorUrl, ProductName, ModelName - опциональные
|
||||||
- User objects - пользовательские поля
|
- User objects - пользовательские поля
|
||||||
@@ -27,6 +26,11 @@
|
|||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
///////////////---DEVICE IDENTIVICATIONS DEFINES---//////////////////
|
///////////////---DEVICE IDENTIVICATIONS DEFINES---//////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup MODBUS_DEVID
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
/** @brief Структура для объекта (идентификатора устройства модбас) */
|
/** @brief Структура для объекта (идентификатора устройства модбас) */
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@@ -48,35 +52,11 @@ typedef struct
|
|||||||
MB_DeviceObjectTypeDef Reserved[0x79];
|
MB_DeviceObjectTypeDef Reserved[0x79];
|
||||||
|
|
||||||
MB_DeviceObjectTypeDef User[MODBUS_NUMB_OF_USEROBJECTS];
|
MB_DeviceObjectTypeDef User[MODBUS_NUMB_OF_USEROBJECTS];
|
||||||
}MB_DeviceIdentificationTypeDef;
|
}MB_DeviceIdentificationsTypeDef;
|
||||||
extern MB_DeviceIdentificationTypeDef MB_DEVID;
|
extern MB_DeviceIdentificationsTypeDef MB_DEVID;
|
||||||
void MB_DeviceInentificationInit(void);
|
void MB_DeviceInentificationInit(void);
|
||||||
///////////////---DEVICE IDENTIVICATIONS DEFINES---//////////////////
|
///////////////---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---////////////////////
|
////////////////////---MODBUS FUNCTION DEFINES---////////////////////
|
||||||
@@ -85,15 +65,20 @@ extern MB_DiagnosticsInfoTypeDef MB_DINFO;
|
|||||||
* @brief Инициализация объектов
|
* @brief Инициализация объектов
|
||||||
* @details С помозью этого дефайна инициализируются объекты в @ref MB_DeviceInentificationInit
|
* @details С помозью этого дефайна инициализируются объекты в @ref MB_DeviceInentificationInit
|
||||||
*/
|
*/
|
||||||
#define MB_ObjectInit(_p_obj_, _userstring_) (_p_obj_)->length = sizeof(_userstring_);\
|
#define MB_ObjectInit(_p_obj_, _userstring_) \
|
||||||
(_p_obj_)->name = _userstring_;
|
(_p_obj_)->length = sizeof(_userstring_);\
|
||||||
/**
|
(_p_obj_)->name = _userstring_;
|
||||||
|
/**
|
||||||
* @brief Инициализация пользовательских объектов
|
* @brief Инициализация пользовательских объектов
|
||||||
* @details С помозью этого дефайна инициализируются пользовательские объекты в MB_DeviceInentificationInit
|
* @details С помозью этого дефайна инициализируются пользовательские объекты в MB_DeviceInentificationInit
|
||||||
*/
|
*/
|
||||||
#define MB_UserObjectInit(_pinfostruct_, _user_numb_) MB_ObjectInit(&(_pinfostruct_)->User[_user_numb_], MODBUS_USEROBJECT##_user_numb_##_NAME)
|
#define MB_UserObjectInit(_pinfostruct_, _user_numb_) MB_ObjectInit(&(_pinfostruct_)->User[_user_numb_], MODBUS_USEROBJECT##_user_numb_##_NAME)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** MODBUS_DEVID
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
////////////////////---MODBUS MESSAGE DEFINES---/////////////////////
|
////////////////////---MODBUS MESSAGE DEFINES---/////////////////////
|
||||||
|
|
||||||
|
|
||||||
@@ -101,25 +86,76 @@ extern MB_DiagnosticsInfoTypeDef MB_DINFO;
|
|||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup MODBUS_REQ_DEFID_API API for Device Identifications
|
||||||
|
* @ingroup MODBUS_REQUEST_MSG
|
||||||
|
* @brief API для чтения идентификторов из ответа в режиме мастер
|
||||||
|
* @details Примеры использования:
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* // Пример 1: Получить VendorName (ID = 0x00)
|
||||||
|
* uint8_t length;
|
||||||
|
* char vendor_name[64];
|
||||||
|
* if(MB_RespGet_ObjectById(&MODBUS_MSG, 0x00, vendor_name, &length))
|
||||||
|
* {
|
||||||
|
* // получено
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* // Пример 2: Перебрать все объекты в сообщении
|
||||||
|
* uint8_t obj_id, obj_length;
|
||||||
|
* char obj_data[256];
|
||||||
|
*
|
||||||
|
* int obj_count = MB_RespGet_NumberOfObjects(&MODBUS_MSG);
|
||||||
|
* printf("Total objects: %d\n", obj_count);
|
||||||
|
*
|
||||||
|
* for(int i = 0; i < obj_count; i++)
|
||||||
|
* {
|
||||||
|
* if(MB_RespGet_ObjectByIndex(&MODBUS_MSG, i, &obj_id, obj_data, &obj_length))
|
||||||
|
* {
|
||||||
|
* // получено
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* @endcode
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Получить количество объектов в сообщении */
|
||||||
|
int MB_RespGet_NumberOfObjects(RS_MsgTypeDef *modbus_msg);
|
||||||
|
/* Найти объект по ID в сообщении */
|
||||||
|
int MB_RespGet_ObjectById(RS_MsgTypeDef *modbus_msg, uint8_t obj_id, char *obj_data, uint8_t *obj_length);
|
||||||
|
/* Получить объект по индексу в сообщении */
|
||||||
|
int MB_RespGet_ObjectByIndex(RS_MsgTypeDef *modbus_msg, int index, uint8_t *obj_id, char *obj_data, uint8_t *obj_length);
|
||||||
|
|
||||||
|
|
||||||
|
/** MODBUS_REQ_DEFID_API
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup MODBUS_DEVID
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Записать Один Объект Идентификатора в массив данных */
|
||||||
|
void MB_WriteSingleObjectToMessage(char *mbdata, unsigned *ind, MB_DeviceObjectTypeDef *obj);
|
||||||
|
/* Записать Массив Объектов Идентификатора в массив данных */
|
||||||
|
void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj);
|
||||||
|
|
||||||
|
/** MODBUS_DEVID
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
//---------PROCESS MODBUS COMMAND FUNCTIONS---------
|
//---------PROCESS MODBUS COMMAND FUNCTIONS---------
|
||||||
/**
|
/**
|
||||||
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
|
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
|
||||||
@{
|
@{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Write Object of Device Identification to MessageData */
|
/* Обработать функцию Read Device Identifications (43/14 - 0x2B/0E) */
|
||||||
void MB_WriteSingleObjectToMessage(char *mbdata, unsigned *ind, MB_DeviceObjectTypeDef *obj);
|
uint8_t MB_Process_Read_Device_Identifications(RS_MsgTypeDef *modbus_msg);
|
||||||
/* Write Object of Device Identification to MessageData */
|
|
||||||
void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj);
|
|
||||||
/* Proccess command Read Device Identification (43/14 - 0x2B/0E) */
|
|
||||||
uint8_t MB_Proccess_Read_Device_Identification(RS_MsgTypeDef *modbus_msg);
|
|
||||||
/** MODBUS_CMD_PROCESS_FUNCTIONS
|
/** MODBUS_CMD_PROCESS_FUNCTIONS
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||||
|
|
||||||
#endif //__MODBUS_DEVID_H_
|
#endif //__MODBUS_DEVID_H_
|
||||||
|
|
||||||
/** MODBUS_DEVID
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
146
Modbus/Inc/modbus_diag.h
Normal file
146
Modbus/Inc/modbus_diag.h
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @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---////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup MODBUS_DIAG
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @brief Режимы работы устройства */
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
MODBUS_NORMAL_MODE = 0,
|
||||||
|
MODBUS_LISTEN_ONLY_MODE = 1
|
||||||
|
} MB_DeviceModeTypeDef;
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Структура со диагностической информацией устройства модбас */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint16_t DiagnosticRegister; ///< Регистр диагностики. 0 бит - overrun. Остальное заполняется пользователем
|
||||||
|
MB_DeviceModeTypeDef DeviceMode;///< Режим устройства - NORMAL/LISTEN_ONLY
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint16_t BusMessage; ///< Все принятые фреймы modbus на линии (с всех адресов)
|
||||||
|
uint16_t BusCommunicationErr; ///< Ошибки при приеме фрейма modbus
|
||||||
|
uint16_t BusExceptionErr; ///< Ошибки при обработке фрейма modbus
|
||||||
|
uint16_t SlaveMessage; ///< Принятые сообщения (только запросы на адрес данного устройства)
|
||||||
|
uint16_t SlaveNoResponse; ///< Счетчик сколько мы раз не ответили на запрос
|
||||||
|
uint16_t SlaveNAK; ///< Счетчик аномальной ошибки при обработке фрейма
|
||||||
|
uint16_t SlaveBusy; ///< Счетчик принятых запросов когда устройство занято. Здесь не работает: из-за архитектуры отследить невозможно
|
||||||
|
uint16_t BusCharacterOverrun; ///< Overrun Error
|
||||||
|
} Counters;
|
||||||
|
} MB_DiagnosticsInfoTypeDef;
|
||||||
|
|
||||||
|
extern MB_DiagnosticsInfoTypeDef MB_DIAG;
|
||||||
|
|
||||||
|
/////////////////---DEVICE DIAGNOSTICS DEFINES---////////////////////
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||||
|
|
||||||
|
/* Инициализация диагностических счетчиков */
|
||||||
|
void MB_DiagnosticsInit(void);
|
||||||
|
|
||||||
|
/** MODBUS_DIAG
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup MODBUS_REQ_DIAG_API API for Diagnostics
|
||||||
|
* @ingroup MODBUS_REQUEST_MSG
|
||||||
|
* @brief API для чтения диагностической информации из ответа в режиме мастер
|
||||||
|
* @details Примеры использования:
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* // Получить данные диагностики (значение счетчика)
|
||||||
|
* uint16_t counter_value;
|
||||||
|
* if(MB_RespGet_Diagnostic(&MODBUS_MSG, &counter_value))
|
||||||
|
* {
|
||||||
|
* printf("Counter value: %d\n", counter_value);
|
||||||
|
* }
|
||||||
|
* @endcode
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
int MB_RespGet_Diagnostic(RS_MsgTypeDef *modbus_msg, uint16_t *data);
|
||||||
|
|
||||||
|
/** MODBUS_REQ_DIAG_API
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS
|
||||||
|
@{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Выставить бит в регистре диагностике */
|
||||||
|
int MB_Diagnostics_WriteBit(int bit_num, int bit_state);
|
||||||
|
/*ь Прочитать состояние бита диагностического регистра */
|
||||||
|
int MB_Diagnostics_GetBit(int bit_num);
|
||||||
|
/* Получение текущего режима устройства */
|
||||||
|
MB_DeviceModeTypeDef MB_GetDeviceMode(void);
|
||||||
|
|
||||||
|
|
||||||
|
/* Функции для обновления счетчиков диагностики */
|
||||||
|
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);
|
||||||
|
/** MODBUS_CMD_PROCESS_FUNCTIONS
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------PROCESS MODBUS COMMAND FUNCTIONS---------
|
||||||
|
/**
|
||||||
|
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
|
||||||
|
@{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Обработка команды диагностики (0x08) */
|
||||||
|
uint8_t MB_Process_Diagnostics(RS_MsgTypeDef *modbus_msg);
|
||||||
|
|
||||||
|
/** MODBUS_CMD_PROCESS_FUNCTIONS
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||||
|
|
||||||
|
#endif //__MODBUS_DIAG_H_
|
||||||
|
|
||||||
|
/** MODBUS_DIAG
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
@@ -5,7 +5,6 @@
|
|||||||
******************************************************************************
|
******************************************************************************
|
||||||
@addtogroup MODBUS_INS Input Register Tools
|
@addtogroup MODBUS_INS Input Register Tools
|
||||||
@ingroup MODBUS_INTERNAL
|
@ingroup MODBUS_INTERNAL
|
||||||
@{
|
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* @details
|
* @details
|
||||||
Модуль обработки команд для регистров хранения (Holding Registers):
|
Модуль обработки команд для регистров хранения (Holding Registers):
|
||||||
@@ -13,7 +12,7 @@
|
|||||||
- Запись одиночного регистра (0x06)
|
- Запись одиночного регистра (0x06)
|
||||||
- Запись множества регистров (0x10)
|
- Запись множества регистров (0x10)
|
||||||
|
|
||||||
@section Регистры хранения:
|
@section Регистры хранения:
|
||||||
- Read/Write доступ
|
- Read/Write доступ
|
||||||
- 16-битные значения (uint16_t)
|
- 16-битные значения (uint16_t)
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
@@ -29,12 +28,12 @@
|
|||||||
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
|
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
|
||||||
@{
|
@{
|
||||||
*/
|
*/
|
||||||
/* Proccess command Read Holding Registers (03 - 0x03) */
|
/* Обработать функцию Read Holding Registers (03 - 0x03) */
|
||||||
uint8_t MB_Proccess_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg);
|
uint8_t MB_Process_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg);
|
||||||
/* Proccess command Write Single Coils (06 - 0x06) */
|
/* Обработать функцию Write Single Coils (06 - 0x06) */
|
||||||
uint8_t MB_Proccess_Write_Single_Reg(RS_MsgTypeDef *modbus_msg);
|
uint8_t MB_Process_Write_Single_Reg(RS_MsgTypeDef *modbus_msg);
|
||||||
/* Proccess command Write Multiple Register (16 - 0x10) */
|
/* Обработать функцию Write Multiple Register (16 - 0x10) */
|
||||||
uint8_t MB_Proccess_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg);
|
uint8_t MB_Process_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg);
|
||||||
|
|
||||||
/** MODBUS_CMD_PROCESS_FUNCTIONS
|
/** MODBUS_CMD_PROCESS_FUNCTIONS
|
||||||
* @}
|
* @}
|
||||||
@@ -42,7 +41,3 @@ uint8_t MB_Proccess_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg);
|
|||||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||||
|
|
||||||
#endif //__MODBUS_HOLDREGS_H_
|
#endif //__MODBUS_HOLDREGS_H_
|
||||||
|
|
||||||
/** MODBUS_INS
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
@@ -5,13 +5,12 @@
|
|||||||
******************************************************************************
|
******************************************************************************
|
||||||
@addtogroup MODBUS_HOLD Holding Registers Tools
|
@addtogroup MODBUS_HOLD Holding Registers Tools
|
||||||
@ingroup MODBUS_INTERNAL
|
@ingroup MODBUS_INTERNAL
|
||||||
@{
|
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* @details
|
* @details
|
||||||
Модуль обработки команд для входных регистров (Input Registers):
|
Модуль обработки команд для входных регистров (Input Registers):
|
||||||
- Чтение множества регистров (0x04)
|
- Чтение множества регистров (0x04)
|
||||||
|
|
||||||
@section Входные регистры:
|
@section Входные регистры:
|
||||||
- Read-Only доступ
|
- Read-Only доступ
|
||||||
- 16-битные значения
|
- 16-битные значения
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
@@ -24,13 +23,13 @@
|
|||||||
|
|
||||||
//---------PROCESS MODBUS COMMAND FUNCTIONS---------
|
//---------PROCESS MODBUS COMMAND FUNCTIONS---------
|
||||||
/**
|
/**
|
||||||
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS Proccess Functions
|
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS Internal Process Functions
|
||||||
* @ingroup MODBUS_FUNCTIONS
|
* @ingroup MODBUS_INTERNAL
|
||||||
* @brief Функции обработки запросов модбас
|
* @brief Функции обработки запросов модбас
|
||||||
@{
|
@{
|
||||||
*/
|
*/
|
||||||
/* Proccess command Read Input Registers (04 - 0x04) */
|
/* Обработать функцию Read Input Registers (04 - 0x04) */
|
||||||
uint8_t MB_Proccess_Read_Input_Regs(RS_MsgTypeDef *modbus_msg);
|
uint8_t MB_Process_Read_Input_Regs(RS_MsgTypeDef *modbus_msg);
|
||||||
|
|
||||||
/** MODBUS_CMD_PROCESS_FUNCTIONS
|
/** MODBUS_CMD_PROCESS_FUNCTIONS
|
||||||
* @}
|
* @}
|
||||||
@@ -38,6 +37,3 @@ uint8_t MB_Proccess_Read_Input_Regs(RS_MsgTypeDef *modbus_msg);
|
|||||||
/////////////////////////---FUNCTIONS---/////////////////////////////
|
/////////////////////////---FUNCTIONS---/////////////////////////////
|
||||||
|
|
||||||
#endif //__MODBUS_INPUTREGS_H_
|
#endif //__MODBUS_INPUTREGS_H_
|
||||||
/** MODBUS_HOLD
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
126
Modbus/Inc/modbus_master.h
Normal file
126
Modbus/Inc/modbus_master.h
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @file modbus_master.h
|
||||||
|
* @brief Главный заголовочный файл Modbus библиотеки
|
||||||
|
******************************************************************************
|
||||||
|
@addtogroup MODBUS_MASTER Modbus master funtions
|
||||||
|
@ingroup MODBUS_CMD_PROCESS_FUNCTIONS
|
||||||
|
******************************************************************************
|
||||||
|
* @details
|
||||||
|
Модуль реализации обработки UART сообщение в режиме мастер
|
||||||
|
******************************************************************************/
|
||||||
|
#ifndef __MODBUS_MASTER_H_
|
||||||
|
#define __MODBUS_MASTER_H_
|
||||||
|
|
||||||
|
#include "rs_message.h"
|
||||||
|
|
||||||
|
#ifdef MODBUS_ENABLE_MASTER
|
||||||
|
#define MODBUS_MODE_MASTER 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup MODBUS_REQUEST_MSG API for Master Requests
|
||||||
|
* @ingroup MODBUS_FUNCTIONS
|
||||||
|
* @brief Макросы для создания запросов в режиме мастер
|
||||||
|
* @details Примеры использования:
|
||||||
|
* @code
|
||||||
|
* // Чтение 10 holding registers начиная с адреса 0
|
||||||
|
* RS_MsgTypeDef read_msg = MB_REQUEST_READ_HOLDING_REGS(1, 0, 10);
|
||||||
|
*
|
||||||
|
* // Запись одного coil
|
||||||
|
* RS_MsgTypeDef write_coil_msg = MB_REQUEST_WRITE_SINGLE_COIL(1, 5, 1);
|
||||||
|
*
|
||||||
|
* // Диагностический запрос
|
||||||
|
* RS_MsgTypeDef diag_msg = MB_REQUEST_RETURN_BUS_MESSAGE_COUNT(1);
|
||||||
|
*
|
||||||
|
* // Идентификация устройства
|
||||||
|
* RS_MsgTypeDef dev_id_msg = MB_REQUEST_READ_DEVICE_ID_BASIC(1);
|
||||||
|
* @endcode
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
//---------КЛАССИЧЕСКИЕ ДАННЫЕ-----------
|
||||||
|
RS_MsgTypeDef MB_REQUEST_READ_COILS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity);
|
||||||
|
RS_MsgTypeDef MB_REQUEST_READ_DISCRETE_INPUTS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity);
|
||||||
|
RS_MsgTypeDef MB_REQUEST_READ_HOLDING_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity);
|
||||||
|
RS_MsgTypeDef MB_REQUEST_READ_INPUT_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity);
|
||||||
|
RS_MsgTypeDef MB_REQUEST_WRITE_SINGLE_COIL(uint8_t slave_addr, uint16_t coil_addr, uint8_t value);
|
||||||
|
RS_MsgTypeDef MB_REQUEST_WRITE_SINGLE_REG(uint8_t slave_addr, uint16_t reg_addr, uint16_t value);
|
||||||
|
RS_MsgTypeDef MB_REQUEST_WRITE_MULTIPLE_COILS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity, uint8_t *coils_data);
|
||||||
|
RS_MsgTypeDef MB_REQUEST_WRITE_MULTIPLE_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity, uint16_t *regs_data);
|
||||||
|
|
||||||
|
//---------ДИАГНОСТИЧЕСКИЕ ДАННЫЕ-----------
|
||||||
|
RS_MsgTypeDef MB_REQUEST_DIAGNOSTIC_QUERY(uint8_t slave_addr, uint16_t sub_function, uint16_t data);
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_QUERY_DATA(uint8_t slave_addr);
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RESTART_COMMUNICATIONS(uint8_t slave_addr, uint16_t data);
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_DIAGNOSTIC_REGISTER(uint8_t slave_addr);
|
||||||
|
RS_MsgTypeDef MB_REQUEST_FORCE_LISTEN_ONLY_MODE(uint8_t slave_addr);
|
||||||
|
RS_MsgTypeDef MB_REQUEST_CLEAR_COUNTERS_AND_DIAGNOSTIC_REGISTER(uint8_t slave_addr);
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_BUS_MESSAGE_COUNT(uint8_t slave_addr);
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_BUS_COMMUNICATION_ERROR_COUNT(uint8_t slave_addr);
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_EXCEPTION_ERROR_COUNT(uint8_t slave_addr);
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_MESSAGE_COUNT(uint8_t slave_addr);
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_NO_RESPONSE_COUNT(uint8_t slave_addr);
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_NAK_COUNT(uint8_t slave_addr);
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_BUSY_COUNT(uint8_t slave_addr);
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_BUS_CHARACTER_OVERRUN_COUNT(uint8_t slave_addr);
|
||||||
|
|
||||||
|
//---------ИДЕНТИФИКАТОРЫ МОДБАС-----------
|
||||||
|
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_BASIC(uint8_t slave_addr);
|
||||||
|
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_REGULAR(uint8_t slave_addr);
|
||||||
|
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_EXTENDED(uint8_t slave_addr);
|
||||||
|
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_SPECIFIC(uint8_t slave_addr, uint8_t object_id);
|
||||||
|
/** MODBUS_REQUEST_MSG
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup MODBUS_REGS_API API for Registers
|
||||||
|
* @ingroup MODBUS_REQUEST_MSG
|
||||||
|
* @brief API для чтения регистров из ответа в режиме мастер
|
||||||
|
* @details Примеры использования:
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* // Пример: Запросили 10 регистров с адреса 100, хотим получить значение регистра 105
|
||||||
|
* uint16_t reg_value;
|
||||||
|
* if(MB_RespGet_RegisterValue(&MODBUS_MSG, 105, ®_value))
|
||||||
|
* {
|
||||||
|
* printf("Register 105 value: %d\n", reg_value);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* // Пример: Получить все запрошенные регистры
|
||||||
|
* for(int addr = MODBUS_MSG.Addr; addr < MODBUS_MSG.Addr + MODBUS_MSG.Qnt; addr++)
|
||||||
|
* {
|
||||||
|
* uint16_t value;
|
||||||
|
* if(MB_RespGet_RegisterValue(&MODBUS_MSG, addr, &value))
|
||||||
|
* {
|
||||||
|
* printf("Register %d: %d\n", addr, value);
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* @endcode
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
int MB_RespGet_RegisterValue(RS_MsgTypeDef *modbus_msg, uint16_t reg_addr, uint16_t *reg_value);
|
||||||
|
|
||||||
|
|
||||||
|
/** MODBUS_REQ_REGS_API
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup MODBUS_MASTER
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Сбор сообщения в буфер UART в режиме мастер (фрейм мастера из msg -> uart) */
|
||||||
|
RS_StatusTypeDef MB_Master_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff);
|
||||||
|
/* Парс сообщения в режиме мастер (фрейм слейва из uart -> msg) */
|
||||||
|
RS_StatusTypeDef MB_Master_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff);
|
||||||
|
|
||||||
|
/** MODBUS_MASTER
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif //__MODBUS_MASTER_H_
|
||||||
36
Modbus/Inc/modbus_slave.h
Normal file
36
Modbus/Inc/modbus_slave.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @file modbus_slave.h
|
||||||
|
* @brief Главный заголовочный файл Modbus библиотеки
|
||||||
|
******************************************************************************
|
||||||
|
@addtogroup MODBUS_SLAVE Modbus slave funtions
|
||||||
|
@ingroup MODBUS_CMD_PROCESS_FUNCTIONS
|
||||||
|
******************************************************************************
|
||||||
|
* @details
|
||||||
|
Модуль реализации обработки UART сообщение в режиме слейв
|
||||||
|
******************************************************************************/
|
||||||
|
#ifndef __MODBUS_SLAVE_H_
|
||||||
|
#define __MODBUS_SLAVE_H_
|
||||||
|
|
||||||
|
#include "rs_message.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef MODBUS_ENABLE_SLAVE
|
||||||
|
#define MODBUS_MODE_SLAVE 0
|
||||||
|
#endif
|
||||||
|
/**
|
||||||
|
* @addtogroup MODBUS_SLAVE
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Ответ на сообщение в режиме слейва */
|
||||||
|
RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg);
|
||||||
|
/* Сбор сообщения в буфер UART в режиме слейв (фрейм слейва из msg -> uart) */
|
||||||
|
RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff);
|
||||||
|
/* Парс сообщения в режиме слейв (фрейм мастера из uart -> msg) */
|
||||||
|
RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff);
|
||||||
|
|
||||||
|
/** MODBUS_SLAVE
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
#endif //__MODBUS_SLAVE_H_
|
||||||
@@ -11,19 +11,19 @@
|
|||||||
Универсальная библиотека для работы с последовательными протоколами (Modbus, Custom)
|
Универсальная библиотека для работы с последовательными протоколами (Modbus, Custom)
|
||||||
через UART в режиме прерываний с поддержкой таймаутов.
|
через UART в режиме прерываний с поддержкой таймаутов.
|
||||||
|
|
||||||
@section Основные возможности:
|
@section Основные возможности:
|
||||||
- Прием/передача в прерываниях
|
- Прием/передача в прерываниях
|
||||||
- Обработка IDLE линии для определения конца фрейма
|
- Обработка IDLE линии для определения конца фрейма
|
||||||
- Таймауты приема через TIM
|
- Таймауты приема через TIM
|
||||||
- Гибкая настройка размера сообщений
|
- Гибкая настройка размера сообщений
|
||||||
|
|
||||||
@section Использование:
|
@section Использование:
|
||||||
1. Определить структуру сообщения и размеры буфера
|
1. Определить структуру сообщения и размеры буфера
|
||||||
2. Реализовать weak-функции обработки сообщений
|
2. Реализовать weak-функции обработки сообщений
|
||||||
3. Добавить вызовы RS_UART_Handler/RS_TIM_Handler в прерывания
|
3. Добавить вызовы RS_UART_Handler/RS_TIM_Handler в прерывания
|
||||||
4. Инициализировать через RS_Init() и запустить прием RS_Receive_IT()
|
4. Инициализировать через RS_Init() и запустить прием RS_Receive_IT()
|
||||||
|
|
||||||
@section Особенности:
|
@section Особенности:
|
||||||
- Буфер: RS_Buffer[MSG_SIZE_MAX] Общий для приема/передачи
|
- Буфер: RS_Buffer[MSG_SIZE_MAX] Общий для приема/передачи
|
||||||
- Состояния: отслеживается через флаги в RS_HandleTypeDef
|
- Состояния: отслеживается через флаги в RS_HandleTypeDef
|
||||||
- Таймауты: контролируют максимальное время ожидания фрейма
|
- Таймауты: контролируют максимальное время ожидания фрейма
|
||||||
@@ -40,10 +40,6 @@
|
|||||||
#error Define MSG_SIZE_MAX (Maximum size of message). This is necessary to create buffer for UART.
|
#error Define MSG_SIZE_MAX (Maximum size of message). This is necessary to create buffer for UART.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef RX_FIRST_PART_SIZE
|
|
||||||
#error Define RX_FIRST_PART_SIZE (Size of first part of message). This is necessary to receive the first part of the message, from which determine the size of the remaining part of the message.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @cond Заглушки и внутренний недокументированный стаф
|
* @cond Заглушки и внутренний недокументированный стаф
|
||||||
*/
|
*/
|
||||||
@@ -55,14 +51,14 @@
|
|||||||
#define RS_Set_Free(_hRS_) _hRS_->f.RS_Busy = 0
|
#define RS_Set_Free(_hRS_) _hRS_->f.RS_Busy = 0
|
||||||
#define RS_Set_Busy(_hRS_) _hRS_->f.RS_Busy = 1
|
#define RS_Set_Busy(_hRS_) _hRS_->f.RS_Busy = 1
|
||||||
|
|
||||||
#define RS_Set_RX_Flags(_hRS_) _hRS_->f.RX_Busy = 1; _hRS_->f.RX_Done = 0; _hRS_->f.RX_Half = 0
|
#define RS_Set_RX_Flags(_hRS_) _hRS_->f.RX_Busy = 1; _hRS_->f.RX_Done = 0;
|
||||||
#define RS_Set_RX_Active_Flags(_hRS_) _hRS_->f.RX_Ongoing = 1
|
#define RS_Set_RX_Active_Flags(_hRS_) _hRS_->f.RX_Ongoing = 1
|
||||||
|
|
||||||
|
|
||||||
#define RS_Set_TX_Flags(_hRS_) _hRS_->f.TX_Busy = 1; _hRS_->f.TX_Done = 0
|
#define RS_Set_TX_Flags(_hRS_) _hRS_->f.TX_Busy = 1; _hRS_->f.TX_Done = 0
|
||||||
|
|
||||||
#define RS_Reset_RX_Active_Flags(_hRS_) _hRS_->f.RX_Ongoing = 0
|
#define RS_Reset_RX_Active_Flags(_hRS_) _hRS_->f.RX_Ongoing = 0; _hRS_->f.RX_Continue = 0;
|
||||||
#define RS_Reset_RX_Flags(_hRS_) RS_Reset_RX_Active_Flags(_hRS_); _hRS_->f.RX_Busy = 0; _hRS_->f.RX_Done = 0; _hRS_->f.RX_Half = 0
|
#define RS_Reset_RX_Flags(_hRS_) RS_Reset_RX_Active_Flags(_hRS_); _hRS_->f.RX_Busy = 0; _hRS_->f.RX_Done = 0;
|
||||||
#define RS_Reset_TX_Flags(_hRS_) _hRS_->f.TX_Busy = 0; _hRS_->f.TX_Done = 0
|
#define RS_Reset_TX_Flags(_hRS_) _hRS_->f.TX_Busy = 0; _hRS_->f.TX_Done = 0
|
||||||
|
|
||||||
#define RS_Set_RX_End_Flag(_hRS_) _hRS_->f.RX_Done = 1;
|
#define RS_Set_RX_End_Flag(_hRS_) _hRS_->f.RX_Done = 1;
|
||||||
@@ -79,15 +75,16 @@
|
|||||||
#define RS_Is_RX_Busy(_hRS_) (_hRS_->f.RX_Busy == 1)
|
#define RS_Is_RX_Busy(_hRS_) (_hRS_->f.RX_Busy == 1)
|
||||||
#define RS_Is_TX_Busy(_hRS_) (_hRS_->f.TX_Busy == 1)
|
#define RS_Is_TX_Busy(_hRS_) (_hRS_->f.TX_Busy == 1)
|
||||||
|
|
||||||
// направление передачи rs485
|
|
||||||
#ifndef RS_EnableReceive
|
#ifndef printf_rs_err
|
||||||
#define RS_EnableReceive()
|
#define printf_rs_err(...)
|
||||||
#endif
|
|
||||||
#ifndef RS_EnableTransmit
|
|
||||||
#define RS_EnableTransmit()
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef __MYLIBS_INCLUDE_H_
|
#ifndef printf_rs
|
||||||
|
#define printf_rs(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __MYLIBS_CONFIG_H_
|
||||||
// дефайны из mylibs include
|
// дефайны из mylibs include
|
||||||
static int dummy;
|
static int dummy;
|
||||||
#define TrackerTypeDef(num_user_vars) void *
|
#define TrackerTypeDef(num_user_vars) void *
|
||||||
@@ -110,20 +107,24 @@ static int dummy;
|
|||||||
#define TrackerClear_Warn(_cntstruct_)
|
#define TrackerClear_Warn(_cntstruct_)
|
||||||
#define TrackerClear_User(_cntstruct_)
|
#define TrackerClear_User(_cntstruct_)
|
||||||
#define TrackerClear_UserAll(_cntstruct_)
|
#define TrackerClear_UserAll(_cntstruct_)
|
||||||
|
#else
|
||||||
#ifndef printf_rs_err
|
#include "mylibs_include.h"
|
||||||
#define printf_rs_err(...)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef printf_rs
|
|
||||||
#define printf_rs(...)
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef RS_USER_VARS_NUMB
|
#ifndef RS_USER_VARS_NUMB
|
||||||
#define RS_USER_VARS_NUMB 0
|
#define RS_USER_VARS_NUMB 0
|
||||||
#endif
|
#endif
|
||||||
/** @endcond */
|
/** @endcond */
|
||||||
|
|
||||||
|
|
||||||
|
// направление передачи rs485
|
||||||
|
#ifndef RS_EnableReceive
|
||||||
|
#define RS_EnableReceive() ///< Функция изменения направления передачи на ПРИЕМ для RS-485
|
||||||
|
#endif
|
||||||
|
#ifndef RS_EnableTransmit
|
||||||
|
#define RS_EnableTransmit() ///< Функция изменения направления передачи на ПЕРЕДАЧУ для RS-485
|
||||||
|
#endif
|
||||||
////////////////////////////---DEFINES---////////////////////////////
|
////////////////////////////---DEFINES---////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
@@ -149,61 +150,44 @@ typedef enum // RS_StatusTypeDef
|
|||||||
}RS_StatusTypeDef;
|
}RS_StatusTypeDef;
|
||||||
|
|
||||||
|
|
||||||
#define RS_MASTER_START 0x3
|
#define RS_MASTER_MODE_START 0x3 ///< Начало режимов мастера (до него - режим слейв)
|
||||||
/** @brief Enums for RS Modes */
|
/** @brief Enums for RS Modes */
|
||||||
typedef enum // RS_ModeTypeDef
|
typedef enum // RS_ModeTypeDef
|
||||||
{
|
{
|
||||||
RS_SLAVE_ALWAYS_WAIT = 0x01, ///< Slave mode with infinity waiting
|
RS_SLAVE_ALWAYS_WAIT = 0x01, ///< Слейв в постоянном ожидании
|
||||||
RS_SLAVE_TIMEOUT_WAIT = 0x02, ///< Slave mode with waiting with timeout
|
RS_RESERVED = 0x02, ///< резерв
|
||||||
// RS_MASTER = 0x03, ///< Master mode
|
RS_MASTER_REQUEST = 0x03, ///< Мастер с ручным запросом
|
||||||
|
//RS_MASTER_POLLING = 0x04, ///< Мастер с опросом в фоновом режиме
|
||||||
}RS_ModeTypeDef;
|
}RS_ModeTypeDef;
|
||||||
|
|
||||||
/** @brief Enums for RS UART Modes */
|
|
||||||
typedef enum // RS_ITModeTypeDef
|
|
||||||
{
|
|
||||||
BLCK_MODE = 0x00, ///< Blocking mode
|
|
||||||
IT_MODE = 0x01, ///< Interrupt mode
|
|
||||||
}RS_ITModeTypeDef;
|
|
||||||
|
|
||||||
/** @brief Enums for Abort modes */
|
/** @brief Enums for Abort modes */
|
||||||
typedef enum // RS_AbortTypeDef
|
typedef enum // RS_AbortTypeDef
|
||||||
{
|
{
|
||||||
ABORT_TX = 0x01, ///< Abort transmit
|
ABORT_TX = 0x01, ///< Отменить передачу
|
||||||
ABORT_RX = 0x02, ///< Abort receive
|
ABORT_RX = 0x02, ///< Отменить прием
|
||||||
ABORT_RX_TX = 0x03, ///< Abort receive and transmit
|
ABORT_RX_TX = 0x03, ///< Отменить прием и передачу
|
||||||
ABORT_RS = 0x04, ///< Abort uart and reset RS structure
|
ABORT_RS = 0x04, ///< Отменить любую работу UART в целом
|
||||||
}RS_AbortTypeDef;
|
}RS_AbortTypeDef;
|
||||||
|
|
||||||
/** @brief Enums for RX Size modes */
|
|
||||||
typedef enum // RS_RXSizeTypeDef
|
|
||||||
{
|
|
||||||
RS_RX_Size_Const = 0x01, ///< size of receiving message is constant
|
|
||||||
RS_RX_Size_NotConst = 0x02, ///< size of receiving message isnt constant
|
|
||||||
}RS_RXSizeTypeDef;
|
|
||||||
|
|
||||||
|
|
||||||
//-----------STRUCTURE FOR HANDLE RS------------
|
//-----------STRUCTURE FOR HANDLE RS------------
|
||||||
/** @brief Struct for flags RS */
|
/** @brief Struct for flags RS */
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
unsigned RX_Half:1; ///< flag: 0 - receiving msg before ByteCnt, 0 - receiving msg after ByteCnt
|
unsigned RS_Busy:1; ///< 1 - RS занят, 0 - RS свободен
|
||||||
|
unsigned RX_Ongoing:1; ///< 1 - Прием данных в активном состоянии, 0 - Ожидаем начало приема данных
|
||||||
|
|
||||||
unsigned RS_Busy:1; ///< flag: 1 - RS is busy, 0 - RS isnt busy
|
unsigned RX_Busy:1; ///< 1 - Режим приема активен, 0 - Прием не активен
|
||||||
unsigned RX_Ongoing:1; ///< flag: 1 - receiving data right now, 0 - waiting for receiving data
|
unsigned TX_Busy:1; ///< 1 - Режим передачи активен, 0 - Прием не активен
|
||||||
|
|
||||||
unsigned RX_Busy:1; ///< flag: 1 - receiving is active, 0 - receiving isnt active
|
unsigned RX_Done:1; ///< 1 - Прием закончен, 0 - Прием еще в процессе или не инициализирован
|
||||||
unsigned TX_Busy:1; ///< flag: 1 - transmiting is active, 0 - transmiting isnt active
|
unsigned TX_Done:1; ///< 1 - Передача закончена, 0 - Передача еще в процессе или не инициализирована
|
||||||
|
|
||||||
unsigned RX_Done:1; ///< flag: 1 - receiving is done, 0 - receiving isnt done
|
|
||||||
unsigned TX_Done:1; ///< flag: 1 - transmiting is done, 0 - transmiting isnt done
|
|
||||||
|
|
||||||
// setted by user
|
// Выставление следующие флагов определяет пользователь
|
||||||
unsigned RX_Continue:1; ///< flag: 0 - continue receiving, 0 - start receiving from ind = 0
|
unsigned RX_Continue:1; ///< 0 - Продолжить принимать, 0 - Начать прием сначала
|
||||||
unsigned MessageHandled:1; ///< flag: 1 - RS command is handled, 0 - RS command isnt handled yet
|
unsigned MessageHandled:1; ///< 1 - Обработка запроса успешна, 0 - Обработка запроса в процессе или ошибка
|
||||||
unsigned EchoResponse:1; ///< flag: 1 - response with received msg, 0 - response with own msg
|
unsigned EchoResponse:1; ///< 1 - Ответить эхом, 0 - Ответить своим сообщением
|
||||||
unsigned DeferredResponse:1; ///< flag: 1 - response not in interrupt, 0 - response in interrupt
|
unsigned DeferredResponse:1; ///< 1 - Не начинать передачу в IT, 0 - Ответить в прерывании
|
||||||
unsigned DataUpdated:1; ///< flag: 1 - Received command to write colis/resg
|
unsigned DataUpdated:1; ///< 1 - Данные были обновлены
|
||||||
unsigned ReInit_UART:1; ///< flag: 1 - need to reinitialize uart, 0 - nothing
|
|
||||||
}RS_FlagsTypeDef;
|
}RS_FlagsTypeDef;
|
||||||
|
|
||||||
|
|
||||||
@@ -215,25 +199,24 @@ typedef struct
|
|||||||
typedef struct // RS_HandleTypeDef
|
typedef struct // RS_HandleTypeDef
|
||||||
{
|
{
|
||||||
/* MESSAGE */
|
/* MESSAGE */
|
||||||
uint8_t ID; ///< ID of RS "channel"
|
uint8_t ID; ///< ID хендла
|
||||||
RS_MsgTypeDef *pMessagePtr; ///< pointer to message struct
|
RS_MsgTypeDef *pMessagePtr; ///< Указатель на структуру протокола
|
||||||
uint8_t *pBufferPtr; ///< pointer to message buffer
|
uint8_t *pBufferPtr; ///< Указатеь на буфер UART
|
||||||
int32_t RS_Message_Size; ///< size of whole message, not only data
|
int32_t RS_Message_Size; ///< size of whole message, not only data
|
||||||
|
|
||||||
/* HANDLERS and SETTINGS */
|
/* HANDLERS and SETTINGS */
|
||||||
UART_HandleTypeDef *huart; ///< handler for used uart
|
UART_HandleTypeDef *huart; ///< Хендл UART
|
||||||
TIM_HandleTypeDef *htim; ///< handler for used tim
|
TIM_HandleTypeDef *htim; ///< Хендл TIM
|
||||||
RS_ModeTypeDef sRS_Mode; ///< setting: slave or master @ref RS_ModeTypeDef
|
RS_ModeTypeDef sRS_Mode; ///< Настройка: слейв/мастер @ref RS_ModeTypeDef
|
||||||
RS_ITModeTypeDef sRS_IT_Mode; ///< setting: 1 - IT mode, 0 - Blocking mode
|
uint16_t sRS_Timeout; ///< Настройка: Таймаут в тиках таймера
|
||||||
uint16_t sRS_Timeout; ///< setting: timeout in ms
|
void (*pCallback)(void*, void*); ///< Указатель на коллбек: принят ответ в режиме мастер
|
||||||
RS_RXSizeTypeDef sRS_RX_Size_Mode; ///< setting: 1 - not const, 0 - const
|
|
||||||
|
|
||||||
/* FLAGS */
|
/* FLAGS */
|
||||||
RS_FlagsTypeDef f; ///< These flags for controling receive/transmit
|
RS_FlagsTypeDef f; ///< Флаги для контроля приема/передачи
|
||||||
|
|
||||||
/* RS STATUS */
|
/* RS STATUS */
|
||||||
uint32_t lastPacketTick;
|
uint32_t lastPacketTick; ///< Время последнего принятого пакета
|
||||||
RS_StatusTypeDef RS_STATUS; ///< RS status
|
RS_StatusTypeDef RS_STATUS; ///< Статус RS
|
||||||
|
|
||||||
TrackerTypeDef(RS_USER_VARS_NUMB) rs_err;
|
TrackerTypeDef(RS_USER_VARS_NUMB) rs_err;
|
||||||
}RS_HandleTypeDef;
|
}RS_HandleTypeDef;
|
||||||
@@ -247,47 +230,53 @@ extern RS_HandleTypeDef hmodbus1;
|
|||||||
///////////////////////////---FUNCTIONS---///////////////////////////
|
///////////////////////////---FUNCTIONS---///////////////////////////
|
||||||
//----------------FUNCTIONS FOR PROCESSING MESSAGE-------------------
|
//----------------FUNCTIONS FOR PROCESSING MESSAGE-------------------
|
||||||
/*--------------------Defined by users purposes--------------------*/
|
/*--------------------Defined by users purposes--------------------*/
|
||||||
/* Respond accord to received message */
|
/* Пользовательская функция для ответа на запрос по UART */
|
||||||
RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
|
RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
|
||||||
|
|
||||||
/* Collect message in buffer to transmit it */
|
/* Пользовательская функция для обработки принятого ответа по UART */
|
||||||
|
__weak RS_StatusTypeDef RS_Response_Callback(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
|
||||||
|
|
||||||
|
/* Пользовательская функция для сбора сообщения в буфер UART */
|
||||||
RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff);
|
RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff);
|
||||||
|
|
||||||
/* Parse message from buffer to process it */
|
/* Пользовательская функция для парса сообщения из буфера UART */
|
||||||
RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff);
|
RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff);
|
||||||
|
|
||||||
|
|
||||||
//-------------------------GENERAL FUNCTIONS-------------------------
|
//-------------------------GENERAL FUNCTIONS-------------------------
|
||||||
/*-----------------Should be called from main code-----------------*/
|
/*-----------------Should be called from main code-----------------*/
|
||||||
/* Start receive IT */
|
/* Начать прием по прерываниям */
|
||||||
RS_StatusTypeDef RS_Receive_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
|
RS_StatusTypeDef RS_Receive_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
|
||||||
|
|
||||||
/* Start transmit IT */
|
/* Начать передачу по прерываниям */
|
||||||
RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
|
RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
|
||||||
|
|
||||||
/* Initialize UART and handle RS stucture */
|
/* Инициалазация структуры @ref RS_HandleTypeDef */
|
||||||
RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, uint8_t *pRS_BufferPtr);
|
RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, uint8_t *pRS_BufferPtr);
|
||||||
|
|
||||||
/* ReInitialize UART and RS receive */
|
/* Отменить прием/передачу RS/UART */
|
||||||
HAL_StatusTypeDef RS_ReInit_UART(RS_HandleTypeDef *hRS, UART_HandleTypeDef *suart);
|
|
||||||
|
|
||||||
/* Abort RS/UART */
|
|
||||||
RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode);
|
RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode);
|
||||||
//-------------------------GENERAL FUNCTIONS-------------------------
|
//-------------------------GENERAL FUNCTIONS-------------------------
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
//--------------------CALLBACK/HANDLER FUNCTIONS---------------------
|
//--------------------CALLBACK/HANDLER FUNCTIONS---------------------
|
||||||
/* Handle for starting receive */
|
/* Обработчик для начала приема */
|
||||||
RS_StatusTypeDef RS_Handle_Receive_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
|
RS_StatusTypeDef RS_Handle_Receive_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
|
||||||
/* Handle for starting transmit */
|
/* Обработчик для начала передачи */
|
||||||
RS_StatusTypeDef RS_Handle_Transmit_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
|
RS_StatusTypeDef RS_Handle_Transmit_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
|
||||||
/* UART TX Callback: define behaviour after transmiting message */
|
/* UART TX Callback: коллбек после окончания передачи */
|
||||||
RS_StatusTypeDef RS_UART_TxCpltCallback(RS_HandleTypeDef *hRS);
|
RS_StatusTypeDef RS_UART_TxCpltCallback(RS_HandleTypeDef *hRS);
|
||||||
/* Handler for UART */
|
/* Обработчик прерывания UART */
|
||||||
void RS_UART_Handler(RS_HandleTypeDef *hRS);
|
void RS_UART_Handler(RS_HandleTypeDef *hRS);
|
||||||
/* Handler for TIM */
|
/* Обработчик прерывания TIM */
|
||||||
void RS_TIM_Handler(RS_HandleTypeDef *hRS);
|
void RS_TIM_Handler(RS_HandleTypeDef *hRS);
|
||||||
|
/* Запуск таймаута приема. */
|
||||||
|
RS_StatusTypeDef RS_Timeout_Start(RS_HandleTypeDef *hRS);
|
||||||
|
/* Остановка таймаута приема. */
|
||||||
|
RS_StatusTypeDef RS_Timeout_Stop(RS_HandleTypeDef *hRS);
|
||||||
|
/* Обновление (сброс) таймаута приема. */
|
||||||
|
RS_StatusTypeDef RS_Timeout_Update(RS_HandleTypeDef *hRS);
|
||||||
//--------------------CALLBACK/HANDLER FUNCTIONS---------------------
|
//--------------------CALLBACK/HANDLER FUNCTIONS---------------------
|
||||||
///////////////////////////---FUNCTIONS---///////////////////////////
|
///////////////////////////---FUNCTIONS---///////////////////////////
|
||||||
|
|
||||||
|
|||||||
@@ -6,61 +6,61 @@
|
|||||||
* @details
|
* @details
|
||||||
Файл содержит реализацию функций работы с Modbus.
|
Файл содержит реализацию функций работы с Modbus.
|
||||||
|
|
||||||
@section Функции и макросы
|
@section Функции и макросы
|
||||||
|
|
||||||
### Инициализация:
|
### Инициализация:
|
||||||
- MODBUS_SetupHardware() — Инициализация модуля Modbus.
|
- MODBUS_FirstInit() — Инициализация Modbus (подключение UART, TIM)
|
||||||
- MODBUS_Config() — Инициализация модуля Modbus.
|
- MODBUS_Config() — Конфигурацмя Modbus (ID, Timeout).
|
||||||
|
- MODBUS_SlaveStart() — Запуск Modbus как Slave.
|
||||||
### Функции для Modbus
|
- MODBUS_MasterRequest() — Отправить запрос в MODBUS как Master.
|
||||||
- MB_Slave_Response()
|
|
||||||
- MB_Slave_Collect_Message()
|
|
||||||
- MB_Slave_Parse_Message()
|
|
||||||
- MB_Master_Collect_Message()
|
|
||||||
- MB_Master_Parse_Message()
|
|
||||||
|
|
||||||
### Функции для работы с RS (UART):
|
### Функции для работы с RS (UART):
|
||||||
- RS_Parse_Message() / RS_Collect_Message() — Парсинг и сборка сообщения.
|
- RS_Parse_Message() / RS_Collect_Message() — Парсинг и сборка сообщения.
|
||||||
- RS_Response() — Отправка ответа.
|
- RS_Response() — Отправка ответа.
|
||||||
|
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#include "modbus.h"
|
#include "modbus.h"
|
||||||
|
|
||||||
/* MODBUS HANDLES */
|
/* MODBUS HANDLES */
|
||||||
RS_HandleTypeDef hmodbus1;
|
RS_HandleTypeDef hmodbus1; ///< Default Handle for Modbus
|
||||||
RS_MsgTypeDef MODBUS_MSG;
|
RS_MsgTypeDef MODBUS_MSG; ///< Default Message Struct for Modbus
|
||||||
|
|
||||||
/* DEFINE REGISTERS/COILS */
|
/* DEFINE DATA FOR MODBUS */
|
||||||
MB_DeviceIdentificationTypeDef MB_DEVID;
|
MB_DataStructureTypeDef MB_DATA = {0};; ///< Coils & Registers
|
||||||
MB_DataStructureTypeDef MB_DATA = {0};;
|
|
||||||
|
static void MB_DefaultCallback(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg);
|
||||||
|
|
||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
//-----------------------------FOR USER------------------------------
|
//-----------------------------FOR USER------------------------------
|
||||||
/**
|
/**
|
||||||
* @brief Инициализация периферии модбас.
|
* @brief Инициализация периферии модбас.
|
||||||
* @param hmodbus Указатель на хендлер RS
|
* @param hmodbus Указатель на хендлер RS
|
||||||
|
* @param huart Указатель на хендлер UART
|
||||||
|
* @param htim Указатель на хендлер TIM
|
||||||
* @details Подключает хендлы периферии к hmodbus
|
* @details Подключает хендлы периферии к hmodbus
|
||||||
* Конфигурация выставляется по умолчанию из modbus_config.h
|
* Конфигурация выставляется по умолчанию из 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))
|
if((hmodbus == NULL) || (huart == NULL))
|
||||||
{
|
{
|
||||||
return;
|
return HAL_ERROR;
|
||||||
}
|
}
|
||||||
MB_DeviceInentificationInit();
|
MB_DeviceInentificationInit();
|
||||||
//-----------SETUP MODBUS-------------
|
//-----------SETUP MODBUS-------------
|
||||||
// set up modbus: MB_RX_Size_NotConst and Timeout enable
|
// set up modbus: MB_RX_Size_NotConst and Timeout enable
|
||||||
hmodbus1.ID = MODBUS_DEVICE_ID;
|
hmodbus->ID = MODBUS_DEVICE_ID;
|
||||||
hmodbus1.sRS_Timeout = MODBUS_TIMEOUT;
|
hmodbus->sRS_Timeout = MODBUS_TIMEOUT;
|
||||||
hmodbus1.sRS_Mode = RS_SLAVE_ALWAYS_WAIT;
|
hmodbus->sRS_Mode = RS_SLAVE_ALWAYS_WAIT;
|
||||||
hmodbus1.sRS_RX_Size_Mode = RS_RX_Size_NotConst;
|
|
||||||
|
|
||||||
// INIT
|
// INIT
|
||||||
hmodbus1.RS_STATUS = RS_Init(hmodbus, huart, htim, 0);
|
hmodbus->RS_STATUS = RS_Init(hmodbus, huart, htim, 0);
|
||||||
|
|
||||||
RS_EnableReceive();
|
RS_EnableReceive();
|
||||||
|
|
||||||
|
if(hmodbus->RS_STATUS == RS_OK)
|
||||||
|
return HAL_OK;
|
||||||
|
else
|
||||||
|
return HAL_ERROR;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @brief Программная конфигурация модбас.
|
* @brief Программная конфигурация модбас.
|
||||||
@@ -69,460 +69,115 @@ void MODBUS_SetupHardware(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart,
|
|||||||
* @param master Режим мастер (пока не сделан)
|
* @param master Режим мастер (пока не сделан)
|
||||||
* @details Конфигурирует ID, таймаут и режим hmodbus
|
* @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)
|
if(hmodbus == NULL)
|
||||||
{
|
{
|
||||||
return;
|
return HAL_ERROR;
|
||||||
}
|
}
|
||||||
//-----------SETUP MODBUS-------------
|
if(!master)
|
||||||
// set up modbus: MB_RX_Size_NotConst and Timeout enable
|
{
|
||||||
hmodbus->ID = ID;
|
if((ID < 1) || (ID > 247))
|
||||||
|
{
|
||||||
|
return HAL_ERROR;
|
||||||
|
}
|
||||||
|
hmodbus->ID = ID;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
hmodbus->ID = 0;
|
||||||
|
|
||||||
hmodbus->sRS_Timeout = Timeout;
|
hmodbus->sRS_Timeout = Timeout;
|
||||||
if(master)
|
if(master)
|
||||||
hmodbus->sRS_Mode = RS_SLAVE_ALWAYS_WAIT;
|
hmodbus->sRS_Mode = RS_MASTER_REQUEST;
|
||||||
else
|
else
|
||||||
hmodbus->sRS_Mode = RS_SLAVE_ALWAYS_WAIT;
|
hmodbus->sRS_Mode = RS_SLAVE_ALWAYS_WAIT;
|
||||||
hmodbus->sRS_RX_Size_Mode = RS_RX_Size_NotConst;
|
|
||||||
|
return HAL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Запуск слейв модбас.
|
* @brief Запуск слейв модбас.
|
||||||
* @param hmodbus Указатель на хендлер RS.
|
* @param hmodbus Указатель на хендлер RS.
|
||||||
* @param modbus_msg Указатель на структуру сообщения.
|
* @param modbus_msg Указатель на структуру сообщения.
|
||||||
|
(NULL чтобы использовать дефолтную)
|
||||||
* @details Конфигурирует ID, таймаут и режим hmodbus
|
* @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)
|
if(hmodbus == NULL)
|
||||||
{
|
{
|
||||||
return;
|
return HAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(hmodbus->sRS_Mode >= RS_MASTER_MODE_START)
|
||||||
|
{
|
||||||
|
return HAL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
MB_DiagnosticsInit();
|
||||||
|
|
||||||
if(modbus_msg)
|
if(modbus_msg)
|
||||||
RS_Receive_IT(hmodbus, modbus_msg);
|
hmodbus->RS_STATUS = RS_Receive_IT(hmodbus, modbus_msg);
|
||||||
else
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Ответ на сообщение в режиме слейва.
|
* @brief Реквест мастера модбас.
|
||||||
* @param hmodbus Указатель на хендлер RS.
|
* @param hmodbus Указатель на хендлер RS.
|
||||||
* @param modbus_msg Указатель на структуру сообщения.
|
* @param modbus_msg Указатель на структуру сообщения
|
||||||
* @return RS_RES Статус о результате ответа на комманду.
|
* @details Конфигурирует ID, таймаут и режим hmodbus
|
||||||
*/
|
*/
|
||||||
static RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
|
HAL_StatusTypeDef MODBUS_MasterRequest(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, void (*pClbk)(RS_HandleTypeDef*, RS_MsgTypeDef*))
|
||||||
{
|
{
|
||||||
RS_StatusTypeDef MB_RES = 0;
|
if(hmodbus == NULL)
|
||||||
hmodbus->f.MessageHandled = 0;
|
|
||||||
hmodbus->f.EchoResponse = 0;
|
|
||||||
RS_Reset_TX_Flags(hmodbus); // reset flag for correct transmit
|
|
||||||
|
|
||||||
if(hmodbus->ID == 0)
|
|
||||||
{
|
{
|
||||||
hmodbus->RS_STATUS = RS_SKIP;
|
return HAL_ERROR;
|
||||||
return MB_RES;
|
|
||||||
}
|
}
|
||||||
|
if(modbus_msg == NULL)
|
||||||
if(modbus_msg->Func_Code < ERR_VALUES_START)// if no errors after parsing
|
|
||||||
{
|
{
|
||||||
switch (modbus_msg->Func_Code)
|
return HAL_ERROR;
|
||||||
{
|
}
|
||||||
// Read Coils
|
if(hmodbus->sRS_Mode < RS_MASTER_MODE_START)
|
||||||
case MB_R_COILS:
|
{
|
||||||
hmodbus->f.MessageHandled = MB_Proccess_Read_Coils(hmodbus->pMessagePtr);
|
return HAL_ERROR;
|
||||||
break;
|
|
||||||
|
|
||||||
// Read Hodling Registers
|
|
||||||
case MB_R_HOLD_REGS:
|
|
||||||
hmodbus->f.MessageHandled = MB_Proccess_Read_Hold_Regs(hmodbus->pMessagePtr);
|
|
||||||
break;
|
|
||||||
case MB_R_IN_REGS:
|
|
||||||
hmodbus->f.MessageHandled = MB_Proccess_Read_Input_Regs(hmodbus->pMessagePtr);
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
|
||||||
// Write Single Coils
|
|
||||||
case MB_W_COIL:
|
|
||||||
hmodbus->f.MessageHandled = MB_Proccess_Write_Single_Coil(hmodbus->pMessagePtr);
|
|
||||||
if(hmodbus->f.MessageHandled)
|
|
||||||
{
|
|
||||||
hmodbus->f.DataUpdated = 1;
|
|
||||||
hmodbus->f.EchoResponse = 1;
|
|
||||||
hmodbus->RS_Message_Size -= 2; // echo response if write ok (minus 2 cause of two CRC bytes)
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MB_W_HOLD_REG:
|
|
||||||
hmodbus->f.MessageHandled = MB_Proccess_Write_Single_Reg(hmodbus->pMessagePtr);
|
|
||||||
if(hmodbus->f.MessageHandled)
|
|
||||||
{
|
|
||||||
hmodbus->f.DataUpdated = 1;
|
|
||||||
hmodbus->f.EchoResponse = 1;
|
|
||||||
hmodbus->RS_Message_Size -= 2; // echo response if write ok (minus 2 cause of two CRC bytes)
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Write Multiple Coils
|
|
||||||
case MB_W_COILS:
|
|
||||||
hmodbus->f.MessageHandled = MB_Write_Miltuple_Coils(hmodbus->pMessagePtr);
|
|
||||||
if(hmodbus->f.MessageHandled)
|
|
||||||
{
|
|
||||||
hmodbus->f.DataUpdated = 1;
|
|
||||||
hmodbus->f.EchoResponse = 1;
|
|
||||||
hmodbus->RS_Message_Size = 6; // echo response if write ok (withous data bytes)
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Write Multiple Registers
|
|
||||||
case MB_W_HOLD_REGS:
|
|
||||||
hmodbus->f.MessageHandled = MB_Proccess_Write_Miltuple_Regs(hmodbus->pMessagePtr);
|
|
||||||
if(hmodbus->f.MessageHandled)
|
|
||||||
{
|
|
||||||
hmodbus->f.DataUpdated = 1;
|
|
||||||
hmodbus->f.EchoResponse = 1;
|
|
||||||
hmodbus->RS_Message_Size = 6; // echo response if write ok (withous data bytes)
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MB_R_DEVICE_INFO:
|
|
||||||
hmodbus->f.MessageHandled = MB_Proccess_Read_Device_Identification(hmodbus->pMessagePtr);
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* unknown func code */
|
|
||||||
default: modbus_msg->Except_Code = 0x01; /* set exception code: illegal function */
|
|
||||||
}
|
|
||||||
|
|
||||||
if(hmodbus->f.MessageHandled == 0)
|
|
||||||
{
|
|
||||||
TrackerCnt_Warn(hmodbus->rs_err);
|
|
||||||
modbus_msg->Func_Code |= ERR_VALUES_START;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TrackerCnt_Ok(hmodbus->rs_err);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we need response - check that transmit isnt busy
|
if(hmodbus->f.RS_Busy)
|
||||||
if( RS_Is_TX_Busy(hmodbus) )
|
return HAL_BUSY;
|
||||||
RS_Abort(hmodbus, ABORT_TX); // if tx busy - set it free
|
|
||||||
|
if(pClbk) // если задан используем пользовательский коллбек
|
||||||
|
hmodbus->pCallback = (void (*)(void*, void*))(pClbk);
|
||||||
|
else // иначе дефолтный
|
||||||
|
hmodbus->pCallback = (void (*)(void*, void*))(&MB_DefaultCallback);
|
||||||
|
|
||||||
// Transmit right there, or sets (fDeferredResponse) to transmit response in main code
|
hmodbus->RS_STATUS = RS_Transmit_IT(hmodbus, modbus_msg);
|
||||||
if(hmodbus->f.DeferredResponse == 0)
|
|
||||||
{
|
if(hmodbus->RS_STATUS == RS_OK)
|
||||||
MB_RES = RS_Handle_Transmit_Start(hmodbus, modbus_msg);
|
return HAL_OK;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
return HAL_ERROR;
|
||||||
RS_Handle_Receive_Start(hmodbus, modbus_msg);
|
|
||||||
hmodbus->f.DeferredResponse = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
hmodbus->RS_STATUS = MB_RES;
|
|
||||||
return MB_RES;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Сбор сообщения в буфер UART в режиме слейв.
|
static void MB_DefaultCallback(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
|
||||||
* @param hmodbus Указатель на хендлер RS.
|
|
||||||
* @param modbus_msg Указатель на структуру сообщения.
|
|
||||||
* @param modbus_uart_buff Указатель на буффер UART.
|
|
||||||
* @return RS_RES Статус о результате заполнения буфера.
|
|
||||||
*/
|
|
||||||
static RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
|
||||||
{
|
{
|
||||||
int ind = 0; // ind for modbus-uart buffer
|
__NOP();
|
||||||
|
return;
|
||||||
if(hmodbus->f.EchoResponse && hmodbus->f.MessageHandled) // if echo response need
|
|
||||||
ind = hmodbus->RS_Message_Size;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//------INFO ABOUT DATA/MESSAGE------
|
|
||||||
//-----------[first bytes]-----------
|
|
||||||
// set ID of message/user
|
|
||||||
modbus_uart_buff[ind++] = modbus_msg->MbAddr;
|
|
||||||
|
|
||||||
// set dat or err response
|
|
||||||
modbus_uart_buff[ind++] = modbus_msg->Func_Code;
|
|
||||||
|
|
||||||
if (modbus_msg->Func_Code < ERR_VALUES_START) // if no error occur
|
|
||||||
{
|
|
||||||
// fill modbus header
|
|
||||||
if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) // devide identification header
|
|
||||||
{
|
|
||||||
modbus_uart_buff[ind++] = modbus_msg->DevId.MEI_Type;
|
|
||||||
modbus_uart_buff[ind++] = modbus_msg->DevId.ReadDevId;
|
|
||||||
modbus_uart_buff[ind++] = modbus_msg->DevId.Conformity;
|
|
||||||
modbus_uart_buff[ind++] = modbus_msg->DevId.MoreFollows;
|
|
||||||
modbus_uart_buff[ind++] = modbus_msg->DevId.NextObjId;
|
|
||||||
modbus_uart_buff[ind++] = modbus_msg->DevId.NumbOfObj;
|
|
||||||
|
|
||||||
if (modbus_msg->ByteCnt > DATA_SIZE*2) // if ByteCnt less than DATA_SIZE
|
|
||||||
{
|
|
||||||
TrackerCnt_Err(hmodbus->rs_err);
|
|
||||||
return RS_COLLECT_MSG_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//---------------DATA----------------
|
|
||||||
//-----------[data bytes]------------
|
|
||||||
uint8_t *tmp_data_addr = (uint8_t *)modbus_msg->DATA;
|
|
||||||
for(int i = 0; i < modbus_msg->ByteCnt; i++) // filling buffer with data
|
|
||||||
{ // set data
|
|
||||||
modbus_uart_buff[ind++] = *tmp_data_addr;
|
|
||||||
tmp_data_addr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else // modbus data header
|
|
||||||
{
|
|
||||||
// set size of received data
|
|
||||||
if (modbus_msg->ByteCnt <= DATA_SIZE*2) // if ByteCnt less than DATA_SIZE
|
|
||||||
modbus_uart_buff[ind++] = modbus_msg->ByteCnt;
|
|
||||||
else // otherwise return data_size err
|
|
||||||
{
|
|
||||||
TrackerCnt_Err(hmodbus->rs_err);
|
|
||||||
return RS_COLLECT_MSG_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------DATA----------------
|
|
||||||
//-----------[data bytes]------------
|
|
||||||
uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->DATA;
|
|
||||||
for(int i = 0; i < modbus_msg->ByteCnt; i++) // filling buffer with data
|
|
||||||
{ // set data
|
|
||||||
if (i%2 == 0) // HI byte
|
|
||||||
modbus_uart_buff[ind++] = (*tmp_data_addr)>>8;
|
|
||||||
else // LO byte
|
|
||||||
{
|
|
||||||
modbus_uart_buff[ind++] = *tmp_data_addr;
|
|
||||||
tmp_data_addr++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else // if some error occur
|
|
||||||
{ // send expection code
|
|
||||||
modbus_uart_buff[ind++] = modbus_msg->Except_Code;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(ind < 0)
|
|
||||||
return RS_COLLECT_MSG_ERR;
|
|
||||||
|
|
||||||
//---------------CRC----------------
|
|
||||||
//---------[last 16 bytes]----------
|
|
||||||
// calc crc of received data
|
|
||||||
uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind);
|
|
||||||
// write crc to message structure and modbus-uart buffer
|
|
||||||
modbus_msg->MB_CRC = CRC_VALUE;
|
|
||||||
modbus_uart_buff[ind++] = CRC_VALUE;
|
|
||||||
modbus_uart_buff[ind++] = CRC_VALUE >> 8;
|
|
||||||
|
|
||||||
hmodbus->RS_Message_Size = ind;
|
|
||||||
|
|
||||||
return RS_OK; // returns ok
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Определить размер модбас запроса.
|
|
||||||
* @param hRS Указатель на хендлер RS.
|
|
||||||
* @param rx_data_size Указатель на переменную для записи кол-ва байт для принятия.
|
|
||||||
* @return RS_RES Статус о корректности рассчета кол-ва байт для принятия.
|
|
||||||
* @details Определение сколько байтов надо принять по протоколу.
|
|
||||||
*/
|
|
||||||
static int MB_Define_Size_of_Function(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
|
|
||||||
{
|
|
||||||
RS_StatusTypeDef MB_RES = 0;
|
|
||||||
int mb_func_size = 0;
|
|
||||||
|
|
||||||
if ((modbus_msg->Func_Code & ~ERR_VALUES_START) < 0x0F)
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
mb_func_size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
mb_func_size = RX_FIRST_PART_SIZE + mb_func_size; // size of whole message
|
|
||||||
return mb_func_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Парс сообщения в режиме слейв.
|
|
||||||
* @param hmodbus Указатель на хендлер RS.
|
|
||||||
* @param modbus_msg Указатель на структуру сообщения.
|
|
||||||
* @param modbus_uart_buff Указатель на буффер UART.
|
|
||||||
* @return RS_RES Статус о результате заполнения структуры.
|
|
||||||
* @details Заполнение структуры сообщения из буффера UART.
|
|
||||||
*/
|
|
||||||
static RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
|
||||||
{
|
|
||||||
uint32_t check_empty_buff;
|
|
||||||
int ind = 0; // ind for modbus-uart buffer
|
|
||||||
hmodbus->f.RX_Continue = 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;
|
|
||||||
}
|
|
||||||
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) // явная херня
|
|
||||||
{
|
|
||||||
modbus_msg->MbAddr = 0;
|
|
||||||
return RS_SKIP;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) // if it device identification request
|
|
||||||
{
|
|
||||||
modbus_msg->DevId.MEI_Type = modbus_uart_buff[ind++];
|
|
||||||
modbus_msg->DevId.ReadDevId = modbus_uart_buff[ind++];
|
|
||||||
modbus_msg->DevId.NextObjId = modbus_uart_buff[ind++];
|
|
||||||
modbus_msg->ByteCnt = 0;
|
|
||||||
}
|
|
||||||
else // if its classic modbus request
|
|
||||||
{
|
|
||||||
// get address from CMD
|
|
||||||
modbus_msg->Addr = modbus_uart_buff[ind++] << 8;
|
|
||||||
modbus_msg->Addr |= modbus_uart_buff[ind++];
|
|
||||||
|
|
||||||
// get address from CMD
|
|
||||||
modbus_msg->Qnt = modbus_uart_buff[ind++] << 8;
|
|
||||||
modbus_msg->Qnt |= modbus_uart_buff[ind++];
|
|
||||||
}
|
|
||||||
|
|
||||||
if((hmodbus->pMessagePtr->Func_Code == 0x0F) || (hmodbus->pMessagePtr->Func_Code == 0x10))
|
|
||||||
hmodbus->pMessagePtr->ByteCnt = modbus_uart_buff[ind++];
|
|
||||||
else
|
|
||||||
hmodbus->pMessagePtr->ByteCnt = 0;
|
|
||||||
|
|
||||||
//---------------DATA----------------
|
|
||||||
// (optional)
|
|
||||||
if (modbus_msg->ByteCnt != 0)
|
|
||||||
{
|
|
||||||
//check that data size is correct
|
|
||||||
if (modbus_msg->ByteCnt > DATA_SIZE*2)
|
|
||||||
{
|
|
||||||
TrackerCnt_Err(hmodbus->rs_err);
|
|
||||||
modbus_msg->Func_Code |= ERR_VALUES_START;
|
|
||||||
return RS_PARSE_MSG_ERR;
|
|
||||||
}
|
|
||||||
uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->DATA;
|
|
||||||
for(int i = 0; i < modbus_msg->ByteCnt; i++)
|
|
||||||
{ // set data
|
|
||||||
if (i%2 == 0)
|
|
||||||
*tmp_data_addr = ((uint16_t)modbus_uart_buff[ind++] << 8);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*tmp_data_addr |= modbus_uart_buff[ind++];
|
|
||||||
tmp_data_addr++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------CRC----------------
|
|
||||||
//----------[last 16 bits]----------
|
|
||||||
// calc crc of received data
|
|
||||||
uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind);
|
|
||||||
// get crc of received data
|
|
||||||
modbus_msg->MB_CRC = modbus_uart_buff[ind++];
|
|
||||||
modbus_msg->MB_CRC |= modbus_uart_buff[ind++] << 8;
|
|
||||||
// compare crc
|
|
||||||
if (modbus_msg->MB_CRC != CRC_VALUE)
|
|
||||||
{
|
|
||||||
TrackerCnt_Err(hmodbus->rs_err);
|
|
||||||
modbus_msg->Func_Code |= ERR_VALUES_START;
|
|
||||||
}
|
|
||||||
// hmodbus->MB_RESPONSE = MB_CRC_ERR; // set func code - error about wrong crc
|
|
||||||
|
|
||||||
// check is buffer empty
|
|
||||||
check_empty_buff = 0;
|
|
||||||
for(int i=0; i<ind;i++)
|
|
||||||
check_empty_buff += modbus_uart_buff[i];
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Сбор сообщения в буфер UART в режиме мастер.
|
|
||||||
* @param hmodbus Указатель на хендлер RS.
|
|
||||||
* @param modbus_msg Указатель на структуру сообщения.
|
|
||||||
* @param modbus_uart_buff Указатель на буффер UART.
|
|
||||||
* @return RS_RES Статус о результате заполнения буфера.
|
|
||||||
*/
|
|
||||||
static RS_StatusTypeDef MB_Master_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
|
||||||
{
|
|
||||||
return RS_PARSE_MSG_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Парс сообщения в режиме мастер.
|
|
||||||
* @param hmodbus Указатель на хендлер RS.
|
|
||||||
* @param modbus_msg Указатель на структуру сообщения.
|
|
||||||
* @param modbus_uart_buff Указатель на буффер UART.
|
|
||||||
* @return RS_RES Статус о результате заполнения структуры.
|
|
||||||
*/
|
|
||||||
static RS_StatusTypeDef MB_Master_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
|
||||||
{
|
|
||||||
return RS_PARSE_MSG_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Реализация функций из rs_message.c для протокола */
|
/* Реализация функций из rs_message.c для протокола */
|
||||||
RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
|
RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
|
||||||
{
|
{
|
||||||
if(hmodbus->sRS_Mode >= RS_MASTER_START)
|
if(hmodbus->sRS_Mode >= RS_MASTER_MODE_START)
|
||||||
{
|
{
|
||||||
return RS_ERR;
|
return RS_ERR;
|
||||||
}
|
}
|
||||||
@@ -531,7 +186,7 @@ RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_ms
|
|||||||
|
|
||||||
RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
||||||
{
|
{
|
||||||
if(hmodbus->sRS_Mode < RS_MASTER_START)
|
if(hmodbus->sRS_Mode < RS_MASTER_MODE_START)
|
||||||
{
|
{
|
||||||
return MB_Slave_Collect_Message(hmodbus, modbus_msg, modbus_uart_buff);
|
return MB_Slave_Collect_Message(hmodbus, modbus_msg, modbus_uart_buff);
|
||||||
}
|
}
|
||||||
@@ -543,7 +198,7 @@ RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mo
|
|||||||
|
|
||||||
RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
||||||
{
|
{
|
||||||
if(hmodbus->sRS_Mode < RS_MASTER_START)
|
if(hmodbus->sRS_Mode < RS_MASTER_MODE_START)
|
||||||
{
|
{
|
||||||
return MB_Slave_Parse_Message(hmodbus, modbus_msg, modbus_uart_buff);
|
return MB_Slave_Parse_Message(hmodbus, modbus_msg, modbus_uart_buff);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,10 +12,10 @@
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
#include "modbus_coils.h"
|
#include "modbus_coils.h"
|
||||||
|
|
||||||
|
#ifdef MODBUS_ENABLE_COILS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set or Reset Coil at its global address.
|
* @brief Выставить/сбросить коил по глобальному адресу.
|
||||||
* @param Addr Адрес коила.
|
* @param Addr Адрес коила.
|
||||||
* @param WriteVal Что записать в коил: 0 или 1.
|
* @param WriteVal Что записать в коил: 0 или 1.
|
||||||
* @return ExceptionCode Код исключения если коила по адресу не существует, и NO_ERRORS если все ок.
|
* @return ExceptionCode Код исключения если коила по адресу не существует, и NO_ERRORS если все ок.
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
* @details Позволяет обратиться к любому коилу по его глобальному адрессу.
|
* @details Позволяет обратиться к любому коилу по его глобальному адрессу.
|
||||||
Вне зависимости от того как коилы размещены в памяти.
|
Вне зависимости от того как коилы размещены в памяти.
|
||||||
*/
|
*/
|
||||||
MB_ExceptionTypeDef MB_Write_Coil_Global(uint16_t Addr, MB_CoilsOpTypeDef WriteVal)
|
MB_ExceptionTypeDef MB_Coil_Write_Global(uint16_t Addr, MB_CoilsOpTypeDef WriteVal)
|
||||||
{
|
{
|
||||||
//---------CHECK FOR ERRORS----------
|
//---------CHECK FOR ERRORS----------
|
||||||
MB_ExceptionTypeDef Exception = NO_ERRORS;
|
MB_ExceptionTypeDef Exception = NO_ERRORS;
|
||||||
@@ -55,7 +55,7 @@ MB_ExceptionTypeDef MB_Write_Coil_Global(uint16_t Addr, MB_CoilsOpTypeDef WriteV
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read Coil at its global address.
|
* @brief Считать коил по глобальному адресу.
|
||||||
* @param Addr Адрес коила.
|
* @param Addr Адрес коила.
|
||||||
* @param Exception Указатель на переменную для кода исключения, в случа неудачи при чтении.
|
* @param Exception Указатель на переменную для кода исключения, в случа неудачи при чтении.
|
||||||
* @return uint16_t Возвращает весь регистр с маской на запрошенном коиле.
|
* @return uint16_t Возвращает весь регистр с маской на запрошенном коиле.
|
||||||
@@ -63,7 +63,7 @@ MB_ExceptionTypeDef MB_Write_Coil_Global(uint16_t Addr, MB_CoilsOpTypeDef WriteV
|
|||||||
* @details Позволяет обратиться к любому коилу по его глобальному адрессу.
|
* @details Позволяет обратиться к любому коилу по его глобальному адрессу.
|
||||||
Вне зависимости от того как коилы размещены в памяти.
|
Вне зависимости от того как коилы размещены в памяти.
|
||||||
*/
|
*/
|
||||||
uint16_t MB_Read_Coil_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception)
|
uint16_t MB_Coil_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception)
|
||||||
{
|
{
|
||||||
//---------CHECK FOR ERRORS----------
|
//---------CHECK FOR ERRORS----------
|
||||||
MB_ExceptionTypeDef Exception_tmp;
|
MB_ExceptionTypeDef Exception_tmp;
|
||||||
@@ -86,13 +86,58 @@ uint16_t MB_Read_Coil_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Proccess command Read Coils (01 - 0x01).
|
/**
|
||||||
|
* @brief Получить состояние coil в ответе по его адресу
|
||||||
|
* @param modbus_msg Указатель на структуру сообщения
|
||||||
|
* @param coil_addr Адрес coil, состояние которого нужно получить
|
||||||
|
* @param coil_state Указатель для состояния coil (1 - ON, 0 - OFF)
|
||||||
|
* @return 1 - успех, 0 - ошибка или coil_addr вне диапазона запроса
|
||||||
|
*/
|
||||||
|
int MB_RespGet_CoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coil_state)
|
||||||
|
{
|
||||||
|
if(modbus_msg == NULL || coil_state == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Проверяем что ответ связан с коилами
|
||||||
|
if(modbus_msg->Func_Code != MB_R_COILS)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверяем что coil_addr в пределах запрошенного диапазона
|
||||||
|
if(coil_addr < modbus_msg->Addr || coil_addr >= modbus_msg->Addr + modbus_msg->Qnt)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Вычисляем индекс coil в полученных данных
|
||||||
|
uint16_t coil_index = coil_addr - modbus_msg->Addr;
|
||||||
|
|
||||||
|
// Вычисляем байт и бит
|
||||||
|
uint8_t byte_index = coil_index / 8;
|
||||||
|
uint8_t data_index = coil_index / 16;
|
||||||
|
uint8_t bit_index = coil_index % 16;
|
||||||
|
|
||||||
|
// Проверяем что байт существует в данных
|
||||||
|
if(byte_index >= modbus_msg->ByteCnt)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Получаем байт и проверяем бит
|
||||||
|
if(bit_index < 8)
|
||||||
|
*coil_state = (modbus_msg->DATA[data_index] >> (bit_index+8)) & 0x01;
|
||||||
|
else
|
||||||
|
*coil_state = (modbus_msg->DATA[data_index] >> bit_index) & 0x01;
|
||||||
|
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Обработать функцию Read Coils (01 - 0x01).
|
||||||
* @param modbus_msg Указатель на структуру собщения modbus.
|
* @param modbus_msg Указатель на структуру собщения modbus.
|
||||||
* @return fMessageHandled Статус о результате обработки комманды.
|
* @return fMessageHandled Статус о результате обработки комманды.
|
||||||
* @details Обработка команды Read Coils.
|
* @details Обработка команды Read Coils.
|
||||||
*/
|
*/
|
||||||
uint8_t MB_Proccess_Read_Coils(RS_MsgTypeDef *modbus_msg)
|
uint8_t MB_Process_Read_Coils(RS_MsgTypeDef *modbus_msg)
|
||||||
{
|
{
|
||||||
//---------CHECK FOR ERRORS----------
|
//---------CHECK FOR ERRORS----------
|
||||||
uint16_t *coils;
|
uint16_t *coils;
|
||||||
@@ -140,12 +185,12 @@ uint8_t MB_Proccess_Read_Coils(RS_MsgTypeDef *modbus_msg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Proccess command Write Single Coils (05 - 0x05).
|
* @brief Обработать функцию Write Single Coils (05 - 0x05).
|
||||||
* @param modbus_msg Указатель на структуру собщения modbus.
|
* @param modbus_msg Указатель на структуру собщения modbus.
|
||||||
* @return fMessageHandled Статус о результате обработки комманды.
|
* @return fMessageHandled Статус о результате обработки комманды.
|
||||||
* @details Обработка команды Write Single Coils.
|
* @details Обработка команды Write Single Coils.
|
||||||
*/
|
*/
|
||||||
uint8_t MB_Proccess_Write_Single_Coil(RS_MsgTypeDef *modbus_msg)
|
uint8_t MB_Process_Write_Single_Coil(RS_MsgTypeDef *modbus_msg)
|
||||||
{
|
{
|
||||||
//---------CHECK FOR ERRORS----------
|
//---------CHECK FOR ERRORS----------
|
||||||
if ((modbus_msg->Qnt != 0x0000) && (modbus_msg->Qnt != 0xFF00))
|
if ((modbus_msg->Qnt != 0x0000) && (modbus_msg->Qnt != 0xFF00))
|
||||||
@@ -171,12 +216,12 @@ uint8_t MB_Proccess_Write_Single_Coil(RS_MsgTypeDef *modbus_msg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Proccess command Write Multiple Coils (15 - 0x0F).
|
* @brief Обработать функцию Write Multiple Coils (15 - 0x0F).
|
||||||
* @param modbus_msg Указатель на структуру собщения modbus.
|
* @param modbus_msg Указатель на структуру собщения modbus.
|
||||||
* @return fMessageHandled Статус о результате обработки комманды.
|
* @return fMessageHandled Статус о результате обработки комманды.
|
||||||
* @details Обработка команды Write Multiple Coils.
|
* @details Обработка команды Write Multiple Coils.
|
||||||
*/
|
*/
|
||||||
uint8_t MB_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg)
|
uint8_t MB_Process_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg)
|
||||||
{
|
{
|
||||||
//---------CHECK FOR ERRORS----------
|
//---------CHECK FOR ERRORS----------
|
||||||
if (modbus_msg->ByteCnt != Divide_Up(modbus_msg->Qnt, 8))
|
if (modbus_msg->ByteCnt != Divide_Up(modbus_msg->Qnt, 8))
|
||||||
@@ -236,3 +281,14 @@ uint8_t MB_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg)
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
#else //MODBUS_ENABLE_COILS
|
||||||
|
|
||||||
|
|
||||||
|
int MB_RespGet_CoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coil_state) {return 0;}
|
||||||
|
MB_ExceptionTypeDef MB_Coil_Write_Global(uint16_t Addr, MB_CoilsOpTypeDef WriteVal) {return ILLEGAL_FUNCTION;}
|
||||||
|
uint16_t MB_Coil_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception) {return 0;}
|
||||||
|
uint8_t MB_Process_Read_Coils(RS_MsgTypeDef *modbus_msg) {return 0;}
|
||||||
|
uint8_t MB_Process_Write_Single_Coil(RS_MsgTypeDef *modbus_msg) {return 0;}
|
||||||
|
uint8_t MB_Process_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg) {return 0;}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
- Определение указателей на реальные данные в памяти
|
- Определение указателей на реальные данные в памяти
|
||||||
- Поддержка пользовательских массивов регистров и coils
|
- Поддержка пользовательских массивов регистров и coils
|
||||||
|
|
||||||
@section Валидация адресов:
|
@section Валидация адресов:
|
||||||
- MB_Check_Address_For_Arr() - проверка принадлежности адреса массиву
|
- MB_Check_Address_For_Arr() - проверка принадлежности адреса массиву
|
||||||
- MB_DefineRegistersAddress() - получение указателя на регистры
|
- MB_DefineRegistersAddress() - получение указателя на регистры
|
||||||
- MB_DefineCoilsAddress() - получение указателя на coils
|
- MB_DefineCoilsAddress() - получение указателя на coils
|
||||||
@@ -23,7 +23,6 @@
|
|||||||
#include "modbus_devid.h"
|
#include "modbus_devid.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check is address valid for certain array.
|
* @brief Check is address valid for certain array.
|
||||||
* @param Addr Начальный адресс.
|
* @param Addr Начальный адресс.
|
||||||
@@ -77,7 +76,7 @@ MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, u
|
|||||||
// Default holding registers
|
// Default holding registers
|
||||||
if(MB_Check_Address_For_Arr(Addr, Qnt, R_HOLDING_ADDR, R_HOLDING_QNT) == NO_ERRORS)
|
if(MB_Check_Address_For_Arr(Addr, Qnt, R_HOLDING_ADDR, R_HOLDING_QNT) == NO_ERRORS)
|
||||||
{
|
{
|
||||||
*pRegs = MB_Set_Register_Ptr(&MB_DATA.HoldRegs, Addr); // указатель на выбранный по Addr регистр
|
*pRegs = MB_Set_Register_Ptr(&MB_DATA.HoldRegs, Addr - R_HOLDING_ADDR); // указатель на выбранный по Addr регистр
|
||||||
}
|
}
|
||||||
// if address doesnt match any array - return illegal data address response
|
// if address doesnt match any array - return illegal data address response
|
||||||
else
|
else
|
||||||
@@ -90,7 +89,7 @@ MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, u
|
|||||||
// Default input registers
|
// Default input registers
|
||||||
if(MB_Check_Address_For_Arr(Addr, Qnt, R_INPUT_ADDR, R_INPUT_QNT) == NO_ERRORS)
|
if(MB_Check_Address_For_Arr(Addr, Qnt, R_INPUT_ADDR, R_INPUT_QNT) == NO_ERRORS)
|
||||||
{
|
{
|
||||||
*pRegs = MB_Set_Register_Ptr(&MB_DATA.InRegs, Addr); // указатель на выбранный по Addr регистр
|
*pRegs = MB_Set_Register_Ptr(&MB_DATA.InRegs, Addr - R_INPUT_ADDR); // указатель на выбранный по Addr регистр
|
||||||
}
|
}
|
||||||
// if address doesnt match any array - return illegal data address response
|
// if address doesnt match any array - return illegal data address response
|
||||||
else
|
else
|
||||||
@@ -128,7 +127,7 @@ MB_ExceptionTypeDef MB_DefineCoilsAddress(uint16_t **pCoils, uint16_t Addr, uint
|
|||||||
// Default coils
|
// Default coils
|
||||||
if(MB_Check_Address_For_Arr(Addr, Qnt, C_COILS_ADDR, C_COILS_QNT) == NO_ERRORS)
|
if(MB_Check_Address_For_Arr(Addr, Qnt, C_COILS_ADDR, C_COILS_QNT) == NO_ERRORS)
|
||||||
{
|
{
|
||||||
*pCoils = MB_Set_Coil_Reg_Ptr(&MB_DATA.Coils, Addr); // указатель на выбранный по Addr массив коилов
|
*pCoils = MB_Set_Coil_Reg_Ptr(&MB_DATA.Coils, Addr - C_COILS_ADDR); // указатель на выбранный по Addr массив коилов
|
||||||
}
|
}
|
||||||
// if address doesnt match any array - return illegal data address response
|
// if address doesnt match any array - return illegal data address response
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* @file modbus_devid.c
|
* @file modbus_devid.c
|
||||||
* @brief Реализация идентификации устройства Modbus
|
* @brief Реализация идентификаторов устройства Modbus
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* @details
|
* @details
|
||||||
Модуль обработки запросов идентификации устройства через MEI-тип 0x0E:
|
Модуль обработки запросов идентификации устройства через MEI-тип 0x0E:
|
||||||
@@ -9,20 +9,151 @@
|
|||||||
- Поддержка потоковой передачи при большом количестве объектов
|
- Поддержка потоковой передачи при большом количестве объектов
|
||||||
- Автоматический расчет MoreFollows флагов
|
- Автоматический расчет MoreFollows флагов
|
||||||
|
|
||||||
@section Потоковая передача:
|
@section Потоковая передача:
|
||||||
При большом количестве объектов идентификация разбивается на несколько
|
При большом количестве объектов идентификация разбивается на несколько
|
||||||
сообщений с установкой флага MoreFollows и указанием NextObjId для
|
сообщений с установкой флага MoreFollows и указанием NextObjId для
|
||||||
продолжения чтения в следующем запросе.
|
продолжения чтения в следующем запросе.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#include "modbus_devid.h"
|
#include "modbus_devid.h"
|
||||||
|
|
||||||
|
#ifdef MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
|
||||||
|
|
||||||
|
MB_DeviceIdentificationsTypeDef MB_DEVID; ///< Глобальная структура идентификаторов устройства
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Получить количество объектов в сообщении
|
||||||
|
* @param modbus_msg Указатель на структуру сообщения
|
||||||
|
* @return int Количество объектов
|
||||||
|
*/
|
||||||
|
int MB_RespGet_NumberOfObjects(RS_MsgTypeDef *modbus_msg)
|
||||||
|
{
|
||||||
|
if(modbus_msg == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// Проверяем что ответ связан с диагностикой
|
||||||
|
if(modbus_msg->Func_Code != MB_R_DEVICE_INFO)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return modbus_msg->DevId.NumbOfObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Найти объект по ID в сообщении
|
||||||
|
* @param modbus_msg Указатель на структуру сообщения
|
||||||
|
* @param obj_id ID искомого объекта
|
||||||
|
* @param obj_data Буфер для данных объекта (может быть NULL)
|
||||||
|
* @param obj_length Указатель для длины объекта
|
||||||
|
* @return int Найден ли объект (1 - да, 0 - нет)
|
||||||
|
*/
|
||||||
|
int MB_RespGet_ObjectById(RS_MsgTypeDef *modbus_msg, uint8_t obj_id, char *obj_data, uint8_t *obj_length)
|
||||||
|
{
|
||||||
|
if((modbus_msg == NULL) || (obj_data == NULL))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Проверяем что ответ связан с диагностикой
|
||||||
|
if(modbus_msg->Func_Code != MB_R_DEVICE_INFO)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *data = (uint8_t*)modbus_msg->DATA;
|
||||||
|
unsigned ind = 0;
|
||||||
|
|
||||||
|
for(int i = 0; i < modbus_msg->DevId.NumbOfObj; i++)
|
||||||
|
{
|
||||||
|
uint8_t current_id = data[ind++];
|
||||||
|
uint8_t current_length = data[ind++];
|
||||||
|
|
||||||
|
if(current_id == obj_id)
|
||||||
|
{
|
||||||
|
if(obj_length)
|
||||||
|
*obj_length = current_length;
|
||||||
|
|
||||||
|
for(int j = 0; j < current_length; j++)
|
||||||
|
{
|
||||||
|
obj_data[j] = data[ind++];
|
||||||
|
}
|
||||||
|
obj_data[current_length] = '\0'; // добавляем \0
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Пропускаем данные этого объекта
|
||||||
|
ind += current_length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Получить объект по индексу в сообщении
|
||||||
|
* @param modbus_msg Указатель на структуру сообщения
|
||||||
|
* @param index Индекс объекта (0..N-1)
|
||||||
|
* @param obj_id Указатель для ID объекта
|
||||||
|
* @param obj_data Буфер для данных объекта
|
||||||
|
* @param obj_length Указатель для длины объекта
|
||||||
|
* @return int Успешность получения (1 - получен, 0 - не найден)
|
||||||
|
*/
|
||||||
|
int MB_RespGet_ObjectByIndex(RS_MsgTypeDef *modbus_msg, int index, uint8_t *obj_id, char *obj_data, uint8_t *obj_length)
|
||||||
|
{
|
||||||
|
if((modbus_msg == NULL) || (obj_data == NULL))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Проверяем что ответ связан с диагностикой
|
||||||
|
if(modbus_msg->Func_Code != MB_R_DEVICE_INFO)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(index >= modbus_msg->DevId.NumbOfObj)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint8_t *data = (uint8_t*)modbus_msg->DATA;
|
||||||
|
unsigned ind = 0;
|
||||||
|
|
||||||
|
for(int i = 0; i <= index; i++)
|
||||||
|
{
|
||||||
|
uint8_t current_id = data[ind++];
|
||||||
|
uint8_t current_length = data[ind++];
|
||||||
|
|
||||||
|
if(obj_id)
|
||||||
|
*obj_id = current_id;
|
||||||
|
if(obj_length)
|
||||||
|
*obj_length = current_length;
|
||||||
|
|
||||||
|
if(i == index)
|
||||||
|
{
|
||||||
|
for(int j = 0; j < current_length; j++)
|
||||||
|
{
|
||||||
|
obj_data[j] = data[ind++];
|
||||||
|
}
|
||||||
|
obj_data[current_length] = '\0'; // добавляем \0
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Пропускаем данные этого объекта
|
||||||
|
ind += current_length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Write Object of Device Identification to MessageData
|
* @brief Записать Один Объект Идентификатора в массив данных
|
||||||
* @param mbdata Указатель на массив данных в структуре RS_MsgTypeDef.
|
* @param mbdata Указатель на массив данных в структуре RS_MsgTypeDef.
|
||||||
* @return obj Объект для записи.
|
* @return obj Объект для записи.
|
||||||
*/
|
*/
|
||||||
void MB_WriteSingleObjectToMessage(char *mbdata, unsigned *ind, MB_DeviceObjectTypeDef *obj)
|
void MB_WriteSingleObjectToMessage(char *mbdata, unsigned *ind, MB_DeviceObjectTypeDef *obj)
|
||||||
{
|
{
|
||||||
mbdata[(*ind)++] = obj->length;
|
mbdata[(*ind)++] = obj->length;
|
||||||
@@ -34,10 +165,10 @@ void MB_WriteSingleObjectToMessage(char *mbdata, unsigned *ind, MB_DeviceObjectT
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Write Object of Device Identification to MessageData
|
* @brief Записать Массив Объектов Идентификатора в массив данных
|
||||||
* @param mbdata Указатель на массив данных в структуре RS_MsgTypeDef.
|
* @param mbdata Указатель на массив данных в структуре RS_MsgTypeDef.
|
||||||
* @return obj Объект для записи.
|
* @return obj Объект для записи.
|
||||||
*/
|
*/
|
||||||
void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj)
|
void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj)
|
||||||
{
|
{
|
||||||
MB_DeviceObjectTypeDef *obj = (MB_DeviceObjectTypeDef *)&MB_DEVID;
|
MB_DeviceObjectTypeDef *obj = (MB_DeviceObjectTypeDef *)&MB_DEVID;
|
||||||
@@ -85,16 +216,16 @@ void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj)
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Proccess command Read Device Identification (43/14 - 0x2B/0E).
|
* @brief Обработать функцию Read Device Identifications (43/14 - 0x2B/0E).
|
||||||
* @param modbus_msg Указатель на структуру собщения modbus.
|
* @param modbus_msg Указатель на структуру собщения modbus.
|
||||||
* @return fMessageHandled Статус о результате обработки комманды.
|
* @return fMessageHandled Статус о результате обработки комманды.
|
||||||
* @details Обработка команды Write Single Register.
|
* @details Обработка команды Write Single Register.
|
||||||
*/
|
*/
|
||||||
uint8_t MB_Proccess_Read_Device_Identification(RS_MsgTypeDef *modbus_msg)
|
uint8_t MB_Process_Read_Device_Identifications(RS_MsgTypeDef *modbus_msg)
|
||||||
{
|
{
|
||||||
switch(modbus_msg->DevId.ReadDevId)
|
switch(modbus_msg->DevId.ReadDevId)
|
||||||
{
|
{
|
||||||
case MB_BASIC_IDENTIFICATION:
|
case MB_BASIC_IDENTIFICATIONS:
|
||||||
if (modbus_msg->DevId.NextObjId == 0)
|
if (modbus_msg->DevId.NextObjId == 0)
|
||||||
{
|
{
|
||||||
modbus_msg->DevId.NextObjId = 0;
|
modbus_msg->DevId.NextObjId = 0;
|
||||||
@@ -104,7 +235,7 @@ uint8_t MB_Proccess_Read_Device_Identification(RS_MsgTypeDef *modbus_msg)
|
|||||||
modbus_msg->DevId.NumbOfObj = 3;
|
modbus_msg->DevId.NumbOfObj = 3;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MB_REGULAR_IDENTIFICATION:
|
case MB_REGULAR_IDENTIFICATIONS:
|
||||||
if (modbus_msg->DevId.NextObjId == 0)
|
if (modbus_msg->DevId.NextObjId == 0)
|
||||||
{
|
{
|
||||||
modbus_msg->DevId.NextObjId = 3;
|
modbus_msg->DevId.NextObjId = 3;
|
||||||
@@ -114,7 +245,12 @@ uint8_t MB_Proccess_Read_Device_Identification(RS_MsgTypeDef *modbus_msg)
|
|||||||
modbus_msg->DevId.NumbOfObj = 4;
|
modbus_msg->DevId.NumbOfObj = 4;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MB_EXTENDED_IDENTIFICATION:
|
case MB_EXTENDED_IDENTIFICATIONS:
|
||||||
|
if(MODBUS_NUMB_OF_USEROBJECTS <= 0 || MODBUS_NUMB_OF_USEROBJECTS > 128)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (modbus_msg->DevId.NextObjId == 0)
|
if (modbus_msg->DevId.NextObjId == 0)
|
||||||
{
|
{
|
||||||
modbus_msg->DevId.NextObjId = 0x80;
|
modbus_msg->DevId.NextObjId = 0x80;
|
||||||
@@ -124,7 +260,7 @@ uint8_t MB_Proccess_Read_Device_Identification(RS_MsgTypeDef *modbus_msg)
|
|||||||
modbus_msg->DevId.NumbOfObj = MODBUS_NUMB_OF_USEROBJECTS;
|
modbus_msg->DevId.NumbOfObj = MODBUS_NUMB_OF_USEROBJECTS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MB_SPEDIFIC_IDENTIFICATION:
|
case MB_SPEDIFIC_IDENTIFICATIONS:
|
||||||
MB_WriteObjectsToMessage(modbus_msg, modbus_msg->DevId.NextObjId);
|
MB_WriteObjectsToMessage(modbus_msg, modbus_msg->DevId.NextObjId);
|
||||||
modbus_msg->DevId.NumbOfObj = 1;
|
modbus_msg->DevId.NumbOfObj = 1;
|
||||||
break;
|
break;
|
||||||
@@ -136,8 +272,9 @@ uint8_t MB_Proccess_Read_Device_Identification(RS_MsgTypeDef *modbus_msg)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Инициализация идентификаторов.
|
||||||
|
*/
|
||||||
void MB_DeviceInentificationInit(void)
|
void MB_DeviceInentificationInit(void)
|
||||||
{
|
{
|
||||||
MB_ObjectInit(&MB_DEVID.VendorName, MODBUS_VENDOR_NAME);
|
MB_ObjectInit(&MB_DEVID.VendorName, MODBUS_VENDOR_NAME);
|
||||||
@@ -533,3 +670,16 @@ void MB_DeviceInentificationInit(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#else //MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
|
||||||
|
|
||||||
|
/* Получить количество объектов в сообщении */
|
||||||
|
int MB_RespGet_NumberOfObjects(RS_MsgTypeDef *modbus_msg) {return 0;}
|
||||||
|
int MB_RespGet_ObjectById(RS_MsgTypeDef *modbus_msg, uint8_t obj_id, char *obj_data, uint8_t *obj_length) {return 0;}
|
||||||
|
int MB_RespGet_ObjectByIndex(RS_MsgTypeDef *modbus_msg, int index, uint8_t *obj_id, char *obj_data, uint8_t *obj_length) {return 0;}
|
||||||
|
void MB_WriteSingleObjectToMessage(char *mbdata, unsigned *ind, MB_DeviceObjectTypeDef *obj) {}
|
||||||
|
void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj) {}
|
||||||
|
uint8_t MB_Process_Read_Device_Identifications(RS_MsgTypeDef *modbus_msg) {return 0;}
|
||||||
|
void MB_DeviceInentificationInit(void) {}
|
||||||
|
|
||||||
|
#endif
|
||||||
336
Modbus/Src/modbus_diag.c
Normal file
336
Modbus/Src/modbus_diag.c
Normal file
@@ -0,0 +1,336 @@
|
|||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @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 Получить данные диагностики из сообщения (DATA[1])
|
||||||
|
* @param modbus_msg Указатель на структуру сообщения
|
||||||
|
* @param data Указатель куда положить данные
|
||||||
|
* @return 1 - успех, 0 - ошибка
|
||||||
|
*/
|
||||||
|
int MB_RespGet_Diagnostic(RS_MsgTypeDef *modbus_msg, uint16_t *data)
|
||||||
|
{
|
||||||
|
if(modbus_msg == NULL || data == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Проверяем что ответ связан с диагностикой
|
||||||
|
if(modbus_msg->Func_Code != MB_R_DIAGNOSTIC)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*data = modbus_msg->DATA[1];
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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->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;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else //MODBUS_ENABLE_DIAGNOSTICS
|
||||||
|
|
||||||
|
void MB_DiagnosticsInit(void) {}
|
||||||
|
int MB_RespGet_Diagnostic(RS_MsgTypeDef *modbus_msg, uint16_t *data) {return 0;}
|
||||||
|
int MB_Diagnostics_WriteBit(int bit_num, int bit_state) {return 0;}
|
||||||
|
int MB_Diagnostics_GetBit(int bit_num) {return 0;}
|
||||||
|
uint8_t MB_Process_Diagnostics(RS_MsgTypeDef *modbus_msg) {return 0;}
|
||||||
|
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) {}
|
||||||
|
MB_DeviceModeTypeDef MB_GetDeviceMode(void) {return MODBUS_NORMAL_MODE;}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -9,25 +9,28 @@
|
|||||||
- Запись одиночного регистра (0x06) - прямая запись значения
|
- Запись одиночного регистра (0x06) - прямая запись значения
|
||||||
- Запись множественных регистров (0x10) - пакетная запись из буфера
|
- Запись множественных регистров (0x10) - пакетная запись из буфера
|
||||||
|
|
||||||
@section Валидация данных:
|
@section Валидация данных:
|
||||||
- Проверка соответствия количества байт и регистров
|
- Проверка соответствия количества байт и регистров
|
||||||
Валидация адресов через MB_DefineRegistersAddress()
|
Валидация адресов через MB_DefineRegistersAddress()
|
||||||
- Обработка исключений при некорректных запросах
|
- Обработка исключений при некорректных запросах
|
||||||
|
|
||||||
@section Echo-ответы:
|
@section Echo-ответы:
|
||||||
При успешной записи формируется echo-ответ с теми же данными,
|
При успешной записи формируется echo-ответ с теми же данными,
|
||||||
что были в запросе (для функций 0x05, 0x06, 0x0F, 0x10).
|
что были в запросе (для функций 0x05, 0x06, 0x0F, 0x10).
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
#include "modbus_inputregs.h"
|
#include "modbus_inputregs.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef MODBUS_ENABLE_HOLDINGS
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Proccess command Read Holding Registers (03 - 0x03).
|
* @brief Обработать функцию Read Holding Registers (03 - 0x03).
|
||||||
* @param modbus_msg Указатель на структуру собщения modbus.
|
* @param modbus_msg Указатель на структуру собщения modbus.
|
||||||
* @return fMessageHandled Статус о результате обработки комманды.
|
* @return fMessageHandled Статус о результате обработки комманды.
|
||||||
* @details Обработка команды Read Holding Registers.
|
* @details Обработка команды Read Holding Registers.
|
||||||
*/
|
*/
|
||||||
uint8_t MB_Proccess_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg)
|
uint8_t MB_Process_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg)
|
||||||
{
|
{
|
||||||
//---------CHECK FOR ERRORS----------
|
//---------CHECK FOR ERRORS----------
|
||||||
// get origin address for data
|
// get origin address for data
|
||||||
@@ -50,12 +53,12 @@ uint8_t MB_Proccess_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Proccess command Write Single Register (06 - 0x06).
|
* @brief Обработать функцию Write Single Register (06 - 0x06).
|
||||||
* @param modbus_msg Указатель на структуру собщения modbus.
|
* @param modbus_msg Указатель на структуру собщения modbus.
|
||||||
* @return fMessageHandled Статус о результате обработки комманды.
|
* @return fMessageHandled Статус о результате обработки комманды.
|
||||||
* @details Обработка команды Write Single Register.
|
* @details Обработка команды Write Single Register.
|
||||||
*/
|
*/
|
||||||
uint8_t MB_Proccess_Write_Single_Reg(RS_MsgTypeDef *modbus_msg)
|
uint8_t MB_Process_Write_Single_Reg(RS_MsgTypeDef *modbus_msg)
|
||||||
{
|
{
|
||||||
// get origin address for data
|
// get origin address for data
|
||||||
uint16_t *pHoldRegs;
|
uint16_t *pHoldRegs;
|
||||||
@@ -69,12 +72,12 @@ uint8_t MB_Proccess_Write_Single_Reg(RS_MsgTypeDef *modbus_msg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Proccess command Write Multiple Registers (16 - 0x10).
|
* @brief Обработать функцию Write Multiple Registers (16 - 0x10).
|
||||||
* @param modbus_msg Указатель на структуру собщения modbus.
|
* @param modbus_msg Указатель на структуру собщения modbus.
|
||||||
* @return fMessageHandled Статус о результате обработки комманды.
|
* @return fMessageHandled Статус о результате обработки комманды.
|
||||||
* @details Обработка команды Write Multiple Registers.
|
* @details Обработка команды Write Multiple Registers.
|
||||||
*/
|
*/
|
||||||
uint8_t MB_Proccess_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg)
|
uint8_t MB_Process_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg)
|
||||||
{
|
{
|
||||||
//---------CHECK FOR ERRORS----------
|
//---------CHECK FOR ERRORS----------
|
||||||
if (modbus_msg->Qnt*2 != modbus_msg->ByteCnt)
|
if (modbus_msg->Qnt*2 != modbus_msg->ByteCnt)
|
||||||
@@ -95,3 +98,12 @@ uint8_t MB_Proccess_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg)
|
|||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#else //MODBUS_ENABLE_HOLDINGS
|
||||||
|
|
||||||
|
uint8_t MB_Process_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg) {return 0;}
|
||||||
|
uint8_t MB_Process_Write_Single_Reg(RS_MsgTypeDef *modbus_msg) {return 0;}
|
||||||
|
uint8_t MB_Process_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg) {return 0;}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -9,17 +9,18 @@
|
|||||||
Копирование данных из структур устройства в буфер ответа
|
Копирование данных из структур устройства в буфер ответа
|
||||||
- Поддержка знаковых и беззнаковых значений
|
- Поддержка знаковых и беззнаковых значений
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#include "modbus_inputregs.h"
|
#include "modbus_inputregs.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef MODBUS_ENABLE_INPUTS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Proccess command Read Input Registers (04 - 0x04).
|
* @brief Обработать функцию Read Input Registers (04 - 0x04).
|
||||||
* @param modbus_msg Указатель на структуру собщения modbus.
|
* @param modbus_msg Указатель на структуру собщения modbus.
|
||||||
* @return fMessageHandled Статус о результате обработки комманды.
|
* @return fMessageHandled Статус о результате обработки комманды.
|
||||||
* @details Обработка команды Read Input Registers.
|
* @details Обработка команды Read Input Registers.
|
||||||
*/
|
*/
|
||||||
uint8_t MB_Proccess_Read_Input_Regs(RS_MsgTypeDef *modbus_msg)
|
uint8_t MB_Process_Read_Input_Regs(RS_MsgTypeDef *modbus_msg)
|
||||||
{
|
{
|
||||||
//---------CHECK FOR ERRORS----------
|
//---------CHECK FOR ERRORS----------
|
||||||
// get origin address for data
|
// get origin address for data
|
||||||
@@ -43,3 +44,9 @@ uint8_t MB_Proccess_Read_Input_Regs(RS_MsgTypeDef *modbus_msg)
|
|||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else //MODBUS_ENABLE_INPUTS
|
||||||
|
|
||||||
|
uint8_t MB_Process_Read_Input_Regs(RS_MsgTypeDef *modbus_msg) {return 0;}
|
||||||
|
|
||||||
|
#endif
|
||||||
527
Modbus/Src/modbus_master.c
Normal file
527
Modbus/Src/modbus_master.c
Normal file
@@ -0,0 +1,527 @@
|
|||||||
|
/**
|
||||||
|
**************************************************************************
|
||||||
|
* @file modbus_master.c
|
||||||
|
* @brief Модуль для реализации мастера MODBUS.
|
||||||
|
**************************************************************************
|
||||||
|
* @details
|
||||||
|
Файл содержит реализацию функций для работы Modbus в режиме мастера.
|
||||||
|
|
||||||
|
@section Функции и макросы
|
||||||
|
|
||||||
|
- MB_Master_Collect_Message() — Сбор сообщения в режиме мастера
|
||||||
|
- MB_Master_Parse_Message() — Парс сообщения в режиме мастера
|
||||||
|
******************************************************************************/
|
||||||
|
#include "modbus.h"
|
||||||
|
|
||||||
|
#ifdef MODBUS_ENABLE_MASTER
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Получить значение регистра из ответа по его адресу
|
||||||
|
* @param modbus_msg Указатель на структуру сообщения
|
||||||
|
* @param reg_addr Адрес регистра, значение которого нужно получить
|
||||||
|
* @param reg_value Указатель для значения регистра
|
||||||
|
* @return 1 - успех, 0 - ошибка или reg_addr вне диапазона запроса
|
||||||
|
*/
|
||||||
|
int MB_RespGet_RegisterValue(RS_MsgTypeDef *modbus_msg, uint16_t reg_addr, uint16_t *reg_value)
|
||||||
|
{
|
||||||
|
if(modbus_msg == NULL || reg_value == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Проверяем что ответ связан с регистрами
|
||||||
|
if((modbus_msg->Func_Code != MB_R_DISC_IN) &&
|
||||||
|
(modbus_msg->Func_Code != MB_R_HOLD_REGS) &&
|
||||||
|
(modbus_msg->Func_Code != MB_R_IN_REGS))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверяем что reg_addr в пределах запрошенного диапазона
|
||||||
|
if(reg_addr < modbus_msg->Addr || reg_addr >= modbus_msg->Addr + modbus_msg->Qnt)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Вычисляем индекс регистра в полученных данных
|
||||||
|
uint16_t reg_index = reg_addr - modbus_msg->Addr;
|
||||||
|
|
||||||
|
// Проверяем что регистр существует в данных
|
||||||
|
if(reg_index >= modbus_msg->ByteCnt / 2)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Получаем значение регистра
|
||||||
|
*reg_value = modbus_msg->DATA[reg_index];
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Определить размер модбас запроса (МАСТЕР версия).
|
||||||
|
* @param hRS Указатель на хендлер RS.
|
||||||
|
* @param rx_data_size Указатель на переменную для записи кол-ва байт для принятия.
|
||||||
|
* @return RS_RES Статус о корректности рассчета кол-ва байт для принятия.
|
||||||
|
* @details Определение сколько байтов надо принять по протоколу.
|
||||||
|
*/
|
||||||
|
static int MB_Define_Size_of_Function(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
|
||||||
|
{
|
||||||
|
RS_StatusTypeDef MB_RES = 0;
|
||||||
|
int mb_func_size = 0;
|
||||||
|
|
||||||
|
|
||||||
|
// Master mode - calculating response size from slave
|
||||||
|
if (modbus_msg->Func_Code & ERR_VALUES_START)
|
||||||
|
{
|
||||||
|
// Error response: [Addr][Func|0x80][ExceptCode][CRC]
|
||||||
|
mb_func_size = -1; // Only Exception Code
|
||||||
|
}
|
||||||
|
else if (modbus_msg->Func_Code == MB_R_DIAGNOSTIC)
|
||||||
|
{
|
||||||
|
// Diagnostics response: [SubFunc_HI][SubFunc_LO][Data_HI][Data_LO]
|
||||||
|
mb_func_size = 1;
|
||||||
|
}
|
||||||
|
else if (modbus_msg->Func_Code == MB_R_DEVICE_INFO)
|
||||||
|
{
|
||||||
|
// Device identifications: variable size, need to read first to determine
|
||||||
|
mb_func_size = 0; // Will be determined after reading header
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (modbus_msg->Func_Code & ~ERR_VALUES_START)
|
||||||
|
{
|
||||||
|
case 0x01: // Read Coils
|
||||||
|
case 0x02: // Read Discrete Inputs
|
||||||
|
case 0x03: // Read Holding Registers
|
||||||
|
case 0x04: // Read Input Registers
|
||||||
|
// Response: [ByteCount][Data...]
|
||||||
|
mb_func_size = modbus_msg->ByteCnt + 2; // ByteCount + variable data
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x05: // Write Single Coil
|
||||||
|
case 0x06: // Write Single Register
|
||||||
|
// Echo response: [Addr][Value][CRC]
|
||||||
|
mb_func_size = 4; // Address(2) + Value(2)
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0F: // Write Multiple Coils
|
||||||
|
case 0x10: // Write Multiple Registers
|
||||||
|
// Echo response: [Addr][Qty][CRC]
|
||||||
|
mb_func_size = 4; // Address(2) + Quantity(2)
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
mb_func_size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mb_func_size = RX_FIRST_PART_SIZE + mb_func_size; // size of whole message
|
||||||
|
return mb_func_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Сбор сообщения в буфер UART в режиме мастер (фрейм мастера из msg -> uart).
|
||||||
|
* @param hmodbus Указатель на хендлер RS.
|
||||||
|
* @param modbus_msg Указатель на структуру сообщения.
|
||||||
|
* @param modbus_uart_buff Указатель на буффер UART.
|
||||||
|
* @return RS_RES Статус о результате заполнения буфера.
|
||||||
|
*/
|
||||||
|
RS_StatusTypeDef MB_Master_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
||||||
|
{
|
||||||
|
int ind = 0; // ind for modbus-uart buffer
|
||||||
|
|
||||||
|
//------INFO ABOUT DATA/MESSAGE------
|
||||||
|
//-----------[first bytes]-----------
|
||||||
|
// set ID of slave device
|
||||||
|
modbus_uart_buff[ind++] = modbus_msg->MbAddr;
|
||||||
|
|
||||||
|
// set function code
|
||||||
|
modbus_uart_buff[ind++] = modbus_msg->Func_Code;
|
||||||
|
|
||||||
|
if(modbus_msg->Func_Code < ERR_VALUES_START) // if no error occur
|
||||||
|
{
|
||||||
|
// fill modbus header
|
||||||
|
if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) // device identifications request
|
||||||
|
{
|
||||||
|
modbus_uart_buff[ind++] = modbus_msg->DevId.MEI_Type;
|
||||||
|
modbus_uart_buff[ind++] = modbus_msg->DevId.ReadDevId;
|
||||||
|
modbus_uart_buff[ind++] = modbus_msg->DevId.NextObjId;
|
||||||
|
}
|
||||||
|
else if(modbus_msg->Func_Code == MB_R_DIAGNOSTIC)
|
||||||
|
{
|
||||||
|
// Diagnostics: [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 // classic modbus request
|
||||||
|
{
|
||||||
|
// set address
|
||||||
|
modbus_uart_buff[ind++] = modbus_msg->Addr >> 8;
|
||||||
|
modbus_uart_buff[ind++] = modbus_msg->Addr & 0xFF;
|
||||||
|
|
||||||
|
// set quantity
|
||||||
|
modbus_uart_buff[ind++] = modbus_msg->Qnt >> 8;
|
||||||
|
modbus_uart_buff[ind++] = modbus_msg->Qnt & 0xFF;
|
||||||
|
|
||||||
|
// for write multiple functions
|
||||||
|
if((modbus_msg->Func_Code == 0x0F) || (modbus_msg->Func_Code == 0x10))
|
||||||
|
{
|
||||||
|
modbus_uart_buff[ind++] = modbus_msg->ByteCnt;
|
||||||
|
|
||||||
|
// write data bytes
|
||||||
|
uint8_t *tmp_data_addr = (uint8_t *)modbus_msg->DATA;
|
||||||
|
for(int i = 0; i < modbus_msg->ByteCnt; i++)
|
||||||
|
{
|
||||||
|
modbus_uart_buff[ind++] = tmp_data_addr[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ind < 0)
|
||||||
|
return RS_COLLECT_MSG_ERR;
|
||||||
|
|
||||||
|
//---------------CRC----------------
|
||||||
|
//---------[last 2 bytes]----------
|
||||||
|
uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind);
|
||||||
|
modbus_msg->MB_CRC = CRC_VALUE;
|
||||||
|
modbus_uart_buff[ind++] = CRC_VALUE & 0xFF;
|
||||||
|
modbus_uart_buff[ind++] = CRC_VALUE >> 8;
|
||||||
|
|
||||||
|
hmodbus->RS_Message_Size = ind;
|
||||||
|
|
||||||
|
return RS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Парс сообщения в режиме мастер (фрейм слейва из uart -> msg).
|
||||||
|
* @param hmodbus Указатель на хендлер RS.
|
||||||
|
* @param modbus_msg Указатель на структуру сообщения.
|
||||||
|
* @param modbus_uart_buff Указатель на буффер UART.
|
||||||
|
* @return RS_RES Статус о результате заполнения структуры.
|
||||||
|
*/
|
||||||
|
RS_StatusTypeDef MB_Master_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
||||||
|
{
|
||||||
|
int ind = 0; // ind for modbus-uart buffer
|
||||||
|
int expected_size = 0;
|
||||||
|
|
||||||
|
// get ID of slave device
|
||||||
|
modbus_msg->MbAddr = modbus_uart_buff[ind++];
|
||||||
|
|
||||||
|
// get function code (check if error response)
|
||||||
|
modbus_msg->Func_Code = modbus_uart_buff[ind++];
|
||||||
|
|
||||||
|
if(modbus_msg->Func_Code & ERR_VALUES_START) // error response
|
||||||
|
{
|
||||||
|
modbus_msg->Except_Code = modbus_uart_buff[ind++];
|
||||||
|
}
|
||||||
|
else if(modbus_msg->Func_Code < ERR_VALUES_START) // normal response
|
||||||
|
{
|
||||||
|
if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) // device identifications response
|
||||||
|
{
|
||||||
|
modbus_msg->DevId.MEI_Type = modbus_uart_buff[ind++];
|
||||||
|
modbus_msg->DevId.ReadDevId = modbus_uart_buff[ind++];
|
||||||
|
modbus_msg->DevId.Conformity = modbus_uart_buff[ind++];
|
||||||
|
modbus_msg->DevId.MoreFollows = modbus_uart_buff[ind++];
|
||||||
|
modbus_msg->DevId.NextObjId = modbus_uart_buff[ind++];
|
||||||
|
modbus_msg->DevId.NumbOfObj = modbus_uart_buff[ind++];
|
||||||
|
|
||||||
|
modbus_msg->ByteCnt = 0;
|
||||||
|
|
||||||
|
// Парсинг объектов идентификации устройства
|
||||||
|
uint8_t *tmp_data_addr = (uint8_t *)modbus_msg->DATA;
|
||||||
|
int data_index = 0;
|
||||||
|
|
||||||
|
for(int obj = 0; obj < modbus_msg->DevId.NumbOfObj; obj++)
|
||||||
|
{
|
||||||
|
// Читаем ID объекта
|
||||||
|
uint8_t object_id = modbus_uart_buff[ind++];
|
||||||
|
tmp_data_addr[data_index++] = object_id;
|
||||||
|
|
||||||
|
// Читаем длину объекта
|
||||||
|
uint8_t object_length = modbus_uart_buff[ind++];
|
||||||
|
tmp_data_addr[data_index++] = object_length;
|
||||||
|
|
||||||
|
// Читаем данные объекта
|
||||||
|
for(int i = 0; i < object_length; i++)
|
||||||
|
{
|
||||||
|
tmp_data_addr[data_index++] = modbus_uart_buff[ind++];
|
||||||
|
}
|
||||||
|
|
||||||
|
modbus_msg->ByteCnt += (2 + object_length); // ID + длина + данные
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(modbus_msg->Func_Code == MB_R_DIAGNOSTIC)
|
||||||
|
{
|
||||||
|
// Diagnostics response: [SubFunc_HI][SubFunc_LO][Data_HI][Data_LO]
|
||||||
|
modbus_msg->DATA[0] = modbus_uart_buff[ind++] << 8;
|
||||||
|
modbus_msg->DATA[0] |= modbus_uart_buff[ind++];
|
||||||
|
modbus_msg->DATA[1] = modbus_uart_buff[ind++] << 8;
|
||||||
|
modbus_msg->DATA[1] |= modbus_uart_buff[ind++];
|
||||||
|
}
|
||||||
|
else // classic modbus response
|
||||||
|
{
|
||||||
|
// get byte count for read functions
|
||||||
|
if((modbus_msg->Func_Code == 0x01) || (modbus_msg->Func_Code == 0x02) ||
|
||||||
|
(modbus_msg->Func_Code == 0x03) || (modbus_msg->Func_Code == 0x04))
|
||||||
|
{
|
||||||
|
modbus_msg->ByteCnt = modbus_uart_buff[ind++];
|
||||||
|
|
||||||
|
// read data bytes
|
||||||
|
uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->DATA;
|
||||||
|
for(int i = 0; i < modbus_msg->ByteCnt; i++)
|
||||||
|
{
|
||||||
|
if(i % 2 == 0) // HI byte
|
||||||
|
tmp_data_addr[i/2] = (uint16_t)modbus_uart_buff[ind++] << 8;
|
||||||
|
else // LO byte
|
||||||
|
tmp_data_addr[i/2] |= modbus_uart_buff[ind++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// for write functions - echo address and quantity
|
||||||
|
else if((modbus_msg->Func_Code == 0x05) || (modbus_msg->Func_Code == 0x06) ||
|
||||||
|
(modbus_msg->Func_Code == 0x0F) || (modbus_msg->Func_Code == 0x10))
|
||||||
|
{
|
||||||
|
modbus_msg->Addr = modbus_uart_buff[ind++] << 8;
|
||||||
|
modbus_msg->Addr |= modbus_uart_buff[ind++];
|
||||||
|
modbus_msg->Qnt = modbus_uart_buff[ind++] << 8;
|
||||||
|
modbus_msg->Qnt |= modbus_uart_buff[ind++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------CRC----------------
|
||||||
|
//----------[last 2 bytes]----------
|
||||||
|
uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind);
|
||||||
|
modbus_msg->MB_CRC = modbus_uart_buff[ind++];
|
||||||
|
modbus_msg->MB_CRC |= modbus_uart_buff[ind++] << 8;
|
||||||
|
|
||||||
|
if(modbus_msg->MB_CRC != CRC_VALUE)
|
||||||
|
{
|
||||||
|
TrackerCnt_Err(hmodbus->rs_err);
|
||||||
|
return RS_PARSE_MSG_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Сформировать запрос на чтение коилов */
|
||||||
|
RS_MsgTypeDef MB_REQUEST_READ_COILS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity)
|
||||||
|
{
|
||||||
|
RS_MsgTypeDef msg = {slave_addr, MB_R_COILS, {0}, start_addr, quantity, 0, {0}, 0, 0};
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Сформировать запрос на чтение дискретных регистров */
|
||||||
|
RS_MsgTypeDef MB_REQUEST_READ_DISCRETE_INPUTS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity)
|
||||||
|
{
|
||||||
|
RS_MsgTypeDef msg = {slave_addr, MB_R_DISC_IN, {0}, start_addr, quantity, 0, {0}, 0, 0};
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Сформировать запрос на чтение холдинг регистров */
|
||||||
|
RS_MsgTypeDef MB_REQUEST_READ_HOLDING_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity)
|
||||||
|
{
|
||||||
|
RS_MsgTypeDef msg = {slave_addr, MB_R_HOLD_REGS, {0}, start_addr, quantity, 0, {0}, 0, 0};
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Сформировать запрос на чтение инпут регистров */
|
||||||
|
RS_MsgTypeDef MB_REQUEST_READ_INPUT_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity)
|
||||||
|
{
|
||||||
|
RS_MsgTypeDef msg = {slave_addr, MB_R_IN_REGS, {0}, start_addr, quantity, 0, {0}, 0, 0};
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Сформировать запрос на запись одного коила */
|
||||||
|
RS_MsgTypeDef MB_REQUEST_WRITE_SINGLE_COIL(uint8_t slave_addr, uint16_t coil_addr, uint8_t value)
|
||||||
|
{
|
||||||
|
RS_MsgTypeDef msg = {slave_addr, MB_W_COIL, {0}, coil_addr, (value ? 0xFF00 : 0x0000), 0, {0}, 0, 0};
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Сформировать запрос на запись одного регистра */
|
||||||
|
RS_MsgTypeDef MB_REQUEST_WRITE_SINGLE_REG(uint8_t slave_addr, uint16_t reg_addr, uint16_t value)
|
||||||
|
{
|
||||||
|
RS_MsgTypeDef msg = {slave_addr, MB_W_HOLD_REG, {0}, reg_addr, value, 0, {0}, 0, 0};
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Сформировать запрос на запись нескольких регистров */
|
||||||
|
RS_MsgTypeDef MB_REQUEST_WRITE_MULTIPLE_COILS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity, uint8_t *coils_data)
|
||||||
|
{
|
||||||
|
RS_MsgTypeDef msg = {slave_addr, MB_W_COILS, {0}, start_addr, quantity, 0, {0}, 0, 0};
|
||||||
|
|
||||||
|
// Calculate byte count and prepare data
|
||||||
|
uint8_t byte_count = (quantity + 7) / 8;
|
||||||
|
msg.ByteCnt = byte_count;
|
||||||
|
|
||||||
|
// Copy coil data to message DATA array
|
||||||
|
for(int i = 0; i < byte_count; i++) {
|
||||||
|
if(i < DATA_SIZE) {
|
||||||
|
msg.DATA[i] = coils_data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Сформировать запрос на запись нескольких коилов */
|
||||||
|
RS_MsgTypeDef MB_REQUEST_WRITE_MULTIPLE_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity, uint16_t *regs_data)
|
||||||
|
{
|
||||||
|
RS_MsgTypeDef msg = {slave_addr, MB_W_HOLD_REGS, {0}, start_addr, quantity, 0, {0}, 0, 0};
|
||||||
|
|
||||||
|
msg.ByteCnt = quantity * 2; // Each register is 2 bytes
|
||||||
|
|
||||||
|
// Copy register data to message DATA array
|
||||||
|
for(int i = 0; i < quantity && i < DATA_SIZE; i++) {
|
||||||
|
msg.DATA[i] = regs_data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------ДИАГНОСТИЧЕСКИЕ ДАННЫЕ-----------
|
||||||
|
RS_MsgTypeDef MB_REQUEST_DIAGNOSTIC_QUERY(uint8_t slave_addr, uint16_t sub_function, uint16_t data)
|
||||||
|
{
|
||||||
|
RS_MsgTypeDef msg = {slave_addr, MB_R_DIAGNOSTIC, {0}, 0, 0, 0, {sub_function, data}, 0, 0};
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_QUERY_DATA(uint8_t slave_addr)
|
||||||
|
{
|
||||||
|
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0000, 0x0000);
|
||||||
|
}
|
||||||
|
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RESTART_COMMUNICATIONS(uint8_t slave_addr, uint16_t data)
|
||||||
|
{
|
||||||
|
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0001, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_DIAGNOSTIC_REGISTER(uint8_t slave_addr)
|
||||||
|
{
|
||||||
|
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0002, 0x0000);
|
||||||
|
}
|
||||||
|
|
||||||
|
RS_MsgTypeDef MB_REQUEST_FORCE_LISTEN_ONLY_MODE(uint8_t slave_addr)
|
||||||
|
{
|
||||||
|
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0004, 0x0000);
|
||||||
|
}
|
||||||
|
|
||||||
|
RS_MsgTypeDef MB_REQUEST_CLEAR_COUNTERS_AND_DIAGNOSTIC_REGISTER(uint8_t slave_addr)
|
||||||
|
{
|
||||||
|
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x000A, 0x0000);
|
||||||
|
}
|
||||||
|
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_BUS_MESSAGE_COUNT(uint8_t slave_addr)
|
||||||
|
{
|
||||||
|
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x000B, 0x0000);
|
||||||
|
}
|
||||||
|
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_BUS_COMMUNICATION_ERROR_COUNT(uint8_t slave_addr)
|
||||||
|
{
|
||||||
|
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x000C, 0x0000);
|
||||||
|
}
|
||||||
|
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_EXCEPTION_ERROR_COUNT(uint8_t slave_addr)
|
||||||
|
{
|
||||||
|
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x000D, 0x0000);
|
||||||
|
}
|
||||||
|
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_MESSAGE_COUNT(uint8_t slave_addr)
|
||||||
|
{
|
||||||
|
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x000E, 0x0000);
|
||||||
|
}
|
||||||
|
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_NO_RESPONSE_COUNT(uint8_t slave_addr)
|
||||||
|
{
|
||||||
|
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x000F, 0x0000);
|
||||||
|
}
|
||||||
|
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_NAK_COUNT(uint8_t slave_addr)
|
||||||
|
{
|
||||||
|
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0010, 0x0000);
|
||||||
|
}
|
||||||
|
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_BUSY_COUNT(uint8_t slave_addr)
|
||||||
|
{
|
||||||
|
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0011, 0x0000);
|
||||||
|
}
|
||||||
|
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_BUS_CHARACTER_OVERRUN_COUNT(uint8_t slave_addr)
|
||||||
|
{
|
||||||
|
return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0012, 0x0000);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------ИДЕНТИФИКАТОРЫ МОДБАС-----------
|
||||||
|
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_BASIC(uint8_t slave_addr)
|
||||||
|
{
|
||||||
|
RS_MsgTypeDef msg = {slave_addr, MB_R_DEVICE_INFO, {0x0E, 0x01, 0x00, 0, 0, 0}, 0, 0, 0, {0}, 0, 0};
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_REGULAR(uint8_t slave_addr)
|
||||||
|
{
|
||||||
|
RS_MsgTypeDef msg = {slave_addr, MB_R_DEVICE_INFO, {0x0E, 0x02, 0x00, 0, 0, 0}, 0, 0, 0, {0}, 0, 0};
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_EXTENDED(uint8_t slave_addr)
|
||||||
|
{
|
||||||
|
RS_MsgTypeDef msg = {slave_addr, MB_R_DEVICE_INFO, {0x0E, 0x03, 0x00, 0, 0, 0}, 0, 0, 0, {0}, 0, 0};
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_SPECIFIC(uint8_t slave_addr, uint8_t object_id)
|
||||||
|
{
|
||||||
|
RS_MsgTypeDef msg = {slave_addr, MB_R_DEVICE_INFO, {0x0E, 0x04, object_id, 0, 0, 0}, 0, 0, 0, {0}, 0, 0};
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#else
|
||||||
|
RS_MsgTypeDef msg_dummy = {0};
|
||||||
|
|
||||||
|
int MB_RespGet_RegisterValue(RS_MsgTypeDef *modbus_msg, uint16_t reg_addr, uint16_t *reg_value) {return 0;}
|
||||||
|
|
||||||
|
RS_MsgTypeDef MB_REQUEST_READ_COILS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity) {return msg_dummy;}
|
||||||
|
RS_MsgTypeDef MB_REQUEST_READ_DISCRETE_INPUTS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity) {return msg_dummy;}
|
||||||
|
RS_MsgTypeDef MB_REQUEST_READ_HOLDING_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity) {return msg_dummy;}
|
||||||
|
RS_MsgTypeDef MB_REQUEST_READ_INPUT_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity) {return msg_dummy;}
|
||||||
|
RS_MsgTypeDef MB_REQUEST_WRITE_SINGLE_COIL(uint8_t slave_addr, uint16_t coil_addr, uint8_t value) {return msg_dummy;}
|
||||||
|
RS_MsgTypeDef MB_REQUEST_WRITE_SINGLE_REG(uint8_t slave_addr, uint16_t reg_addr, uint16_t value) {return msg_dummy;}
|
||||||
|
RS_MsgTypeDef MB_REQUEST_WRITE_MULTIPLE_COILS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity, uint8_t *coils_data) {return msg_dummy;}
|
||||||
|
RS_MsgTypeDef MB_REQUEST_WRITE_MULTIPLE_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity, uint16_t *regs_data) {return msg_dummy;}
|
||||||
|
|
||||||
|
//---------ДИАГНОСТИЧЕСКИЕ ДАННЫЕ-----------
|
||||||
|
RS_MsgTypeDef MB_REQUEST_DIAGNOSTIC_QUERY(uint8_t slave_addr, uint16_t sub_function, uint16_t data) {return msg_dummy;}
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_QUERY_DATA(uint8_t slave_addr) {return msg_dummy;}
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RESTART_COMMUNICATIONS(uint8_t slave_addr, uint16_t data) {return msg_dummy;}
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_DIAGNOSTIC_REGISTER(uint8_t slave_addr) {return msg_dummy;}
|
||||||
|
RS_MsgTypeDef MB_REQUEST_FORCE_LISTEN_ONLY_MODE(uint8_t slave_addr) {return msg_dummy;}
|
||||||
|
RS_MsgTypeDef MB_REQUEST_CLEAR_COUNTERS_AND_DIAGNOSTIC_REGISTER(uint8_t slave_addr) {return msg_dummy;}
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_BUS_MESSAGE_COUNT(uint8_t slave_addr) {return msg_dummy;}
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_BUS_COMMUNICATION_ERROR_COUNT(uint8_t slave_addr) {return msg_dummy;}
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_EXCEPTION_ERROR_COUNT(uint8_t slave_addr) {return msg_dummy;}
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_MESSAGE_COUNT(uint8_t slave_addr) {return msg_dummy;}
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_NO_RESPONSE_COUNT(uint8_t slave_addr) {return msg_dummy;}
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_NAK_COUNT(uint8_t slave_addr) {return msg_dummy;}
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_BUSY_COUNT(uint8_t slave_addr) {return msg_dummy;}
|
||||||
|
RS_MsgTypeDef MB_REQUEST_RETURN_BUS_CHARACTER_OVERRUN_COUNT(uint8_t slave_addr) {return msg_dummy;}
|
||||||
|
|
||||||
|
//---------ИДЕНТИФИКАТОРЫ МОДБАС-----------
|
||||||
|
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_BASIC(uint8_t slave_addr) {return msg_dummy;}
|
||||||
|
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_REGULAR(uint8_t slave_addr) {return msg_dummy;}
|
||||||
|
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_EXTENDED(uint8_t slave_addr) {return msg_dummy;}
|
||||||
|
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_SPECIFIC(uint8_t slave_addr, uint8_t object_id) {return msg_dummy;}
|
||||||
|
|
||||||
|
RS_StatusTypeDef MB_Master_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff) {return RS_ERR;}
|
||||||
|
RS_StatusTypeDef MB_Master_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff) {return RS_ERR;}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
437
Modbus/Src/modbus_slave.c
Normal file
437
Modbus/Src/modbus_slave.c
Normal file
@@ -0,0 +1,437 @@
|
|||||||
|
/**
|
||||||
|
**************************************************************************
|
||||||
|
* @file modbus_slave.c
|
||||||
|
* @brief Модуль для реализации слейв MODBUS.
|
||||||
|
**************************************************************************
|
||||||
|
* @details
|
||||||
|
Файл содержит реализацию функций для работы Modbus в режиме слейва.
|
||||||
|
|
||||||
|
@section Функции и макросы
|
||||||
|
|
||||||
|
- MB_Slave_Response() — Ответ на запрос
|
||||||
|
- MB_Slave_Collect_Message() — Сбор сообщения в режиме слейва.
|
||||||
|
- MB_Slave_Parse_Message() — Парс сообщения в режиме слейва.
|
||||||
|
******************************************************************************/
|
||||||
|
#include "modbus.h"
|
||||||
|
|
||||||
|
#ifdef MODBUS_ENABLE_SLAVE
|
||||||
|
/**
|
||||||
|
* @brief Ответ на сообщение в режиме слейва.
|
||||||
|
* @param hmodbus Указатель на хендлер RS.
|
||||||
|
* @param modbus_msg Указатель на структуру сообщения.
|
||||||
|
* @return RS_RES Статус о результате ответа на комманду.
|
||||||
|
*/
|
||||||
|
RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
|
||||||
|
{
|
||||||
|
RS_StatusTypeDef MB_RES = 0;
|
||||||
|
hmodbus->f.MessageHandled = 0;
|
||||||
|
hmodbus->f.EchoResponse = 0;
|
||||||
|
RS_Reset_TX_Flags(hmodbus); // reset flag for correct transmit
|
||||||
|
|
||||||
|
MB_Diagnostics_BusMessageCnt();
|
||||||
|
if(hmodbus->ID == 0 || modbus_msg->MbAddr == 0)
|
||||||
|
{
|
||||||
|
MB_Diagnostics_SlaveNoResponseCnt(); // <-- Устройство не отвечает на широковещательные сообщения
|
||||||
|
hmodbus->RS_STATUS = RS_SKIP;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
// Read Coils
|
||||||
|
case MB_R_COILS:
|
||||||
|
hmodbus->f.MessageHandled = MB_Process_Read_Coils(hmodbus->pMessagePtr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Read Hodling Registers
|
||||||
|
case MB_R_HOLD_REGS:
|
||||||
|
hmodbus->f.MessageHandled = MB_Process_Read_Hold_Regs(hmodbus->pMessagePtr);
|
||||||
|
break;
|
||||||
|
case MB_R_IN_REGS:
|
||||||
|
hmodbus->f.MessageHandled = MB_Process_Read_Input_Regs(hmodbus->pMessagePtr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
// Write Single Coils
|
||||||
|
case MB_W_COIL:
|
||||||
|
hmodbus->f.MessageHandled = MB_Process_Write_Single_Coil(hmodbus->pMessagePtr);
|
||||||
|
if(hmodbus->f.MessageHandled)
|
||||||
|
{
|
||||||
|
hmodbus->f.DataUpdated = 1;
|
||||||
|
hmodbus->f.EchoResponse = 1;
|
||||||
|
hmodbus->RS_Message_Size -= 2; // echo response if write ok (minus 2 cause of two CRC bytes)
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MB_W_HOLD_REG:
|
||||||
|
hmodbus->f.MessageHandled = MB_Process_Write_Single_Reg(hmodbus->pMessagePtr);
|
||||||
|
if(hmodbus->f.MessageHandled)
|
||||||
|
{
|
||||||
|
hmodbus->f.DataUpdated = 1;
|
||||||
|
hmodbus->f.EchoResponse = 1;
|
||||||
|
hmodbus->RS_Message_Size -= 2; // echo response if write ok (minus 2 cause of two CRC bytes)
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Write Multiple Coils
|
||||||
|
case MB_W_COILS:
|
||||||
|
hmodbus->f.MessageHandled = MB_Process_Write_Miltuple_Coils(hmodbus->pMessagePtr);
|
||||||
|
if(hmodbus->f.MessageHandled)
|
||||||
|
{
|
||||||
|
hmodbus->f.DataUpdated = 1;
|
||||||
|
hmodbus->f.EchoResponse = 1;
|
||||||
|
hmodbus->RS_Message_Size = 6; // echo response if write ok (withous data bytes)
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Write Multiple Registers
|
||||||
|
case MB_W_HOLD_REGS:
|
||||||
|
hmodbus->f.MessageHandled = MB_Process_Write_Miltuple_Regs(hmodbus->pMessagePtr);
|
||||||
|
if(hmodbus->f.MessageHandled)
|
||||||
|
{
|
||||||
|
hmodbus->f.DataUpdated = 1;
|
||||||
|
hmodbus->f.EchoResponse = 1;
|
||||||
|
hmodbus->RS_Message_Size = 6; // echo response if write ok (withous data bytes)
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MB_R_DEVICE_INFO:
|
||||||
|
hmodbus->f.MessageHandled = MB_Process_Read_Device_Identifications(hmodbus->pMessagePtr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Добавить в switch-case после других case:
|
||||||
|
case MB_R_DIAGNOSTIC:
|
||||||
|
hmodbus->f.MessageHandled = MB_Process_Diagnostics(hmodbus->pMessagePtr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* unknown func code */
|
||||||
|
default:
|
||||||
|
modbus_msg->Except_Code = 0x01; /* set exception code: illegal function */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Проверяем режим устройства - если 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;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TrackerCnt_Ok(hmodbus->rs_err);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we need response - check that transmit isnt busy
|
||||||
|
if( RS_Is_TX_Busy(hmodbus) )
|
||||||
|
RS_Abort(hmodbus, ABORT_TX); // if tx busy - set it free
|
||||||
|
|
||||||
|
// Transmit right there, or sets (fDeferredResponse) to transmit response in main code
|
||||||
|
if(hmodbus->f.DeferredResponse == 0)
|
||||||
|
{
|
||||||
|
MB_RES = RS_Handle_Transmit_Start(hmodbus, modbus_msg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RS_Handle_Receive_Start(hmodbus, modbus_msg);
|
||||||
|
hmodbus->f.DeferredResponse = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
hmodbus->RS_STATUS = MB_RES;
|
||||||
|
return MB_RES;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Сбор сообщения в буфер UART в режиме слейв (фрейм слейва из msg -> uart).
|
||||||
|
* @param hmodbus Указатель на хендлер RS.
|
||||||
|
* @param modbus_msg Указатель на структуру сообщения.
|
||||||
|
* @param modbus_uart_buff Указатель на буффер UART.
|
||||||
|
* @return RS_RES Статус о результате заполнения буфера.
|
||||||
|
*/
|
||||||
|
RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
||||||
|
{
|
||||||
|
int ind = 0; // ind for modbus-uart buffer
|
||||||
|
|
||||||
|
if(hmodbus->f.EchoResponse && hmodbus->f.MessageHandled) // if echo response need
|
||||||
|
ind = hmodbus->RS_Message_Size;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//------INFO ABOUT DATA/MESSAGE------
|
||||||
|
//-----------[first bytes]-----------
|
||||||
|
// set ID of message/user
|
||||||
|
modbus_uart_buff[ind++] = modbus_msg->MbAddr;
|
||||||
|
|
||||||
|
// set dat or err response
|
||||||
|
modbus_uart_buff[ind++] = modbus_msg->Func_Code;
|
||||||
|
|
||||||
|
if (modbus_msg->Func_Code < ERR_VALUES_START) // if no error occur
|
||||||
|
{
|
||||||
|
// fill modbus header
|
||||||
|
if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) // devide identifications header
|
||||||
|
{
|
||||||
|
modbus_uart_buff[ind++] = modbus_msg->DevId.MEI_Type;
|
||||||
|
modbus_uart_buff[ind++] = modbus_msg->DevId.ReadDevId;
|
||||||
|
modbus_uart_buff[ind++] = modbus_msg->DevId.Conformity;
|
||||||
|
modbus_uart_buff[ind++] = modbus_msg->DevId.MoreFollows;
|
||||||
|
modbus_uart_buff[ind++] = modbus_msg->DevId.NextObjId;
|
||||||
|
modbus_uart_buff[ind++] = modbus_msg->DevId.NumbOfObj;
|
||||||
|
|
||||||
|
if (modbus_msg->ByteCnt > DATA_SIZE*2) // if ByteCnt less than DATA_SIZE
|
||||||
|
{
|
||||||
|
TrackerCnt_Err(hmodbus->rs_err);
|
||||||
|
return RS_COLLECT_MSG_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------DATA----------------
|
||||||
|
//-----------[data bytes]------------
|
||||||
|
uint8_t *tmp_data_addr = (uint8_t *)modbus_msg->DATA;
|
||||||
|
for(int i = 0; i < modbus_msg->ByteCnt; i++) // filling buffer with data
|
||||||
|
{ // set data
|
||||||
|
modbus_uart_buff[ind++] = *tmp_data_addr;
|
||||||
|
tmp_data_addr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
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
|
||||||
|
if (modbus_msg->ByteCnt <= DATA_SIZE*2) // if ByteCnt less than DATA_SIZE
|
||||||
|
modbus_uart_buff[ind++] = modbus_msg->ByteCnt;
|
||||||
|
else // otherwise return data_size err
|
||||||
|
{
|
||||||
|
TrackerCnt_Err(hmodbus->rs_err);
|
||||||
|
return RS_COLLECT_MSG_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------DATA----------------
|
||||||
|
//-----------[data bytes]------------
|
||||||
|
uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->DATA;
|
||||||
|
for(int i = 0; i < modbus_msg->ByteCnt; i++) // filling buffer with data
|
||||||
|
{ // set data
|
||||||
|
if (i%2 == 0) // HI byte
|
||||||
|
modbus_uart_buff[ind++] = (*tmp_data_addr)>>8;
|
||||||
|
else // LO byte
|
||||||
|
{
|
||||||
|
modbus_uart_buff[ind++] = *tmp_data_addr;
|
||||||
|
tmp_data_addr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else // if some error occur
|
||||||
|
{ // send expection code
|
||||||
|
modbus_uart_buff[ind++] = modbus_msg->Except_Code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(ind < 0)
|
||||||
|
return RS_COLLECT_MSG_ERR;
|
||||||
|
|
||||||
|
//---------------CRC----------------
|
||||||
|
//---------[last 16 bytes]----------
|
||||||
|
// calc crc of received data
|
||||||
|
uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind);
|
||||||
|
// write crc to message structure and modbus-uart buffer
|
||||||
|
modbus_msg->MB_CRC = CRC_VALUE;
|
||||||
|
modbus_uart_buff[ind++] = CRC_VALUE;
|
||||||
|
modbus_uart_buff[ind++] = CRC_VALUE >> 8;
|
||||||
|
|
||||||
|
hmodbus->RS_Message_Size = ind;
|
||||||
|
|
||||||
|
return RS_OK; // returns ok
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Определить размер модбас запроса (СЛЕЙВ версия).
|
||||||
|
* @param hRS Указатель на хендлер RS.
|
||||||
|
* @param rx_data_size Указатель на переменную для записи кол-ва байт для принятия.
|
||||||
|
* @return RS_RES Статус о корректности рассчета кол-ва байт для принятия.
|
||||||
|
* @details Определение сколько байтов надо принять по протоколу.
|
||||||
|
*/
|
||||||
|
static int MB_Define_Size_of_Function(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
|
||||||
|
{
|
||||||
|
RS_StatusTypeDef MB_RES = 0;
|
||||||
|
int mb_func_size = 0;
|
||||||
|
|
||||||
|
if (modbus_msg->Func_Code == MB_R_DIAGNOSTIC)
|
||||||
|
{
|
||||||
|
mb_func_size = 1;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Парс сообщения в режиме слейв (фрейм мастера из uart -> msg).
|
||||||
|
* @param hmodbus Указатель на хендлер RS.
|
||||||
|
* @param modbus_msg Указатель на структуру сообщения.
|
||||||
|
* @param modbus_uart_buff Указатель на буффер UART.
|
||||||
|
* @return RS_RES Статус о результате заполнения структуры.
|
||||||
|
* @details Заполнение структуры сообщения из буффера UART.
|
||||||
|
*/
|
||||||
|
RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
ind++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) // if it device identifications request
|
||||||
|
{
|
||||||
|
modbus_msg->DevId.MEI_Type = modbus_uart_buff[ind++];
|
||||||
|
modbus_msg->DevId.ReadDevId = modbus_uart_buff[ind++];
|
||||||
|
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
|
||||||
|
modbus_msg->Addr = modbus_uart_buff[ind++] << 8;
|
||||||
|
modbus_msg->Addr |= modbus_uart_buff[ind++];
|
||||||
|
|
||||||
|
// get address from CMD
|
||||||
|
modbus_msg->Qnt = modbus_uart_buff[ind++] << 8;
|
||||||
|
modbus_msg->Qnt |= modbus_uart_buff[ind++];
|
||||||
|
}
|
||||||
|
|
||||||
|
if((hmodbus->pMessagePtr->Func_Code == 0x0F) || (hmodbus->pMessagePtr->Func_Code == 0x10))
|
||||||
|
hmodbus->pMessagePtr->ByteCnt = modbus_uart_buff[ind++];
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
//check that data size is correct
|
||||||
|
if (modbus_msg->ByteCnt > DATA_SIZE*2)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
for(int i = 0; i < modbus_msg->ByteCnt; i++)
|
||||||
|
{ // set data
|
||||||
|
if (i%2 == 0)
|
||||||
|
*tmp_data_addr = ((uint16_t)modbus_uart_buff[ind++] << 8);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*tmp_data_addr |= modbus_uart_buff[ind++];
|
||||||
|
tmp_data_addr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------CRC----------------
|
||||||
|
//----------[last 16 bits]----------
|
||||||
|
// calc crc of received data
|
||||||
|
uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind);
|
||||||
|
// get crc of received data
|
||||||
|
modbus_msg->MB_CRC = modbus_uart_buff[ind++];
|
||||||
|
modbus_msg->MB_CRC |= modbus_uart_buff[ind++] << 8;
|
||||||
|
// compare crc
|
||||||
|
if (modbus_msg->MB_CRC != CRC_VALUE)
|
||||||
|
{
|
||||||
|
MB_Diagnostics_CommunicationErrorCnt();
|
||||||
|
TrackerCnt_Err(hmodbus->rs_err);
|
||||||
|
modbus_msg->Func_Code |= ERR_VALUES_START;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // MODBUS_ENABLE_SLAVE
|
||||||
|
RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) {return RS_ERR;}
|
||||||
|
RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff) {return RS_ERR;}
|
||||||
|
RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff) {return RS_ERR;}
|
||||||
|
#endif
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
- Таймаутов через таймер
|
- Таймаутов через таймер
|
||||||
- Двухстадийного приема (заголовок + данные)
|
- Двухстадийного приема (заголовок + данные)
|
||||||
|
|
||||||
@section Архитектура:
|
@section Архитектура:
|
||||||
В режиме слейв:
|
В режиме слейв:
|
||||||
- Инициализация приема с сообщения с максимальным размером MSG_SIZE_MAX
|
- Инициализация приема с сообщения с максимальным размером MSG_SIZE_MAX
|
||||||
- При срабатывании прерывания IDLE - обработка полученного сообщения
|
- При срабатывании прерывания IDLE - обработка полученного сообщения
|
||||||
@@ -18,11 +18,12 @@
|
|||||||
- Отправка запроса и переход в режим приема сообщения с максимальным размером MSG_SIZE_MAX
|
- Отправка запроса и переход в режим приема сообщения с максимальным размером MSG_SIZE_MAX
|
||||||
- При срабатывании прерывания IDLE - обработка полученного ответа
|
- При срабатывании прерывания IDLE - обработка полученного ответа
|
||||||
|
|
||||||
@section Необходимые обработчики:
|
@section Необходимые обработчики:
|
||||||
- RS_UART_Handler() в UARTx_IRQHandler вместо HAL_UART_IRQHandler()
|
- RS_UART_Handler() в UARTx_IRQHandler вместо HAL_UART_IRQHandler()
|
||||||
- RS_TIM_Handler() в TIMx_IRQHandler вместо HAL_TIM_IRQHandler()
|
- RS_TIM_Handler() в TIMx_IRQHandler вместо HAL_TIM_IRQHandler()
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
#include "rs_message.h"
|
#include "rs_message.h"
|
||||||
|
#include "modbus_diag.h"
|
||||||
|
|
||||||
uint8_t RS_Buffer[MSG_SIZE_MAX]; // uart buffer
|
uint8_t RS_Buffer[MSG_SIZE_MAX]; // uart buffer
|
||||||
|
|
||||||
@@ -34,7 +35,7 @@ extern void RS_TIM_DeInit(TIM_HandleTypeDef *htim);
|
|||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
//-------------------------GENERAL FUNCTIONS-------------------------
|
//-------------------------GENERAL FUNCTIONS-------------------------
|
||||||
/**
|
/**
|
||||||
* @brief Start receive IT.
|
* @brief Начать прием по прерываниям.
|
||||||
* @param hRS Указатель на хендлер RS.
|
* @param hRS Указатель на хендлер RS.
|
||||||
* @param RS_msg Указатель на структуру сообщения.
|
* @param RS_msg Указатель на структуру сообщения.
|
||||||
* @return RS_RES Статус о состоянии RS после инициализации приема.
|
* @return RS_RES Статус о состоянии RS после инициализации приема.
|
||||||
@@ -60,7 +61,7 @@ RS_StatusTypeDef RS_Receive_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
|
|||||||
|
|
||||||
// start receiving
|
// start receiving
|
||||||
__HAL_UART_ENABLE_IT(hRS->huart, UART_IT_IDLE);
|
__HAL_UART_ENABLE_IT(hRS->huart, UART_IT_IDLE);
|
||||||
uart_res = HAL_UART_Receive_IT(hRS->huart, &hRS->pBufferPtr[hRS->RS_Message_Size], MSG_SIZE_MAX); // receive until ByteCnt+1 byte,
|
uart_res = HAL_UART_Receive_IT(hRS->huart, &hRS->pBufferPtr[hRS->RS_Message_Size], MSG_SIZE_MAX); // receive until ByteCnt+1 byte,
|
||||||
// then in Callback restart receive for rest bytes
|
// then in Callback restart receive for rest bytes
|
||||||
|
|
||||||
// if receive isnt started - abort RS
|
// if receive isnt started - abort RS
|
||||||
@@ -82,7 +83,7 @@ RS_StatusTypeDef RS_Receive_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Start transmit IT.
|
* @brief Начать передачу по прерываниям.
|
||||||
* @param hRS Указатель на хендлер RS.
|
* @param hRS Указатель на хендлер RS.
|
||||||
* @param RS_msg Указатель на структуру сообщения.
|
* @param RS_msg Указатель на структуру сообщения.
|
||||||
* @return RS_RES Статус о состоянии RS после инициализации передачи.
|
* @return RS_RES Статус о состоянии RS после инициализации передачи.
|
||||||
@@ -111,7 +112,6 @@ RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
|
|||||||
|
|
||||||
//----------INITIALIZE TRANSMIT-------------
|
//----------INITIALIZE TRANSMIT-------------
|
||||||
RS_EnableTransmit();
|
RS_EnableTransmit();
|
||||||
// for(int i = 0; i < hRS->sRS_Timeout; i++);
|
|
||||||
|
|
||||||
RS_Set_Busy(hRS); // set RS busy
|
RS_Set_Busy(hRS); // set RS busy
|
||||||
RS_Set_TX_Flags(hRS); // initialize flags for transmit IT
|
RS_Set_TX_Flags(hRS); // initialize flags for transmit IT
|
||||||
@@ -145,13 +145,13 @@ RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initialize UART and handle RS stucture.
|
* @brief Инициалазация структуры @ref RS_HandleTypeDef.
|
||||||
* @param hRS Указатель на хендлер RS.
|
* @param hRS Указатель на хендлер RS.
|
||||||
* @param suart Указатель на структуру с настройками UART.
|
* @param suart Указатель на структуру с настройками UART.
|
||||||
* @param stim Указатель на структуру с настройками таймера.
|
* @param stim Указатель на структуру с настройками таймера.
|
||||||
* @param pRS_BufferPtr Указатель на буффер для приема-передачи по UART. Если он NULL, то поставиться библиотечный буфер.
|
* @param pRS_BufferPtr Указатель на буффер для приема-передачи по UART. Если он NULL, то поставиться библиотечный буфер.
|
||||||
* @return RS_RES Статус о состоянии RS после инициализации.
|
* @return RS_RES Статус о состоянии RS после инициализации.
|
||||||
* @note Инициализация перефирии и структуры для приема-передачи по RS.
|
* @details Инициализация перефирии и структуры для приема-передачи по RS.
|
||||||
*/
|
*/
|
||||||
RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, uint8_t *pRS_BufferPtr)
|
RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, uint8_t *pRS_BufferPtr)
|
||||||
{
|
{
|
||||||
@@ -166,9 +166,6 @@ RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_H
|
|||||||
|
|
||||||
hRS->htim = htim;
|
hRS->htim = htim;
|
||||||
|
|
||||||
if (hRS->sRS_RX_Size_Mode == NULL)
|
|
||||||
return RS_ERR;
|
|
||||||
|
|
||||||
// check that buffer is defined
|
// check that buffer is defined
|
||||||
if (hRS->pBufferPtr == NULL)
|
if (hRS->pBufferPtr == NULL)
|
||||||
{
|
{
|
||||||
@@ -182,7 +179,7 @@ RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_H
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Abort RS/UART.
|
* @brief Отменить прием/передачу RS/UART.
|
||||||
* @param hRS Указатель на хендлер RS.
|
* @param hRS Указатель на хендлер RS.
|
||||||
* @param AbortMode Выбор, что надо отменить.
|
* @param AbortMode Выбор, что надо отменить.
|
||||||
- ABORT_TX: Отмена передачи по ЮАРТ, с очищением флагов TX,
|
- ABORT_TX: Отмена передачи по ЮАРТ, с очищением флагов TX,
|
||||||
@@ -190,20 +187,14 @@ RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_H
|
|||||||
- ABORT_RX_TX: Отмена приема и передачи по ЮАРТ,
|
- ABORT_RX_TX: Отмена приема и передачи по ЮАРТ,
|
||||||
- ABORT_RS: Отмена приема-передачи RS, с очищением всей структуры.
|
- ABORT_RS: Отмена приема-передачи RS, с очищением всей структуры.
|
||||||
* @return RS_RES Статус о состоянии RS после аборта.
|
* @return RS_RES Статус о состоянии RS после аборта.
|
||||||
* @note Отмена работы UART в целом или отмена приема/передачи RS.
|
* @details Отмена работы UART в целом или отмена приема/передачи RS.
|
||||||
Также очищается хендл hRS.
|
Также очищается хендл hRS.
|
||||||
*/
|
*/
|
||||||
RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode)
|
RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode)
|
||||||
{
|
{
|
||||||
HAL_StatusTypeDef uart_res = 0;
|
HAL_StatusTypeDef uart_res = 0;
|
||||||
|
|
||||||
if(hRS->htim)
|
RS_Timeout_Stop(hRS);
|
||||||
{
|
|
||||||
if(hRS->sRS_Timeout) // if timeout setted
|
|
||||||
HAL_TIM_Base_Stop_IT(hRS->htim); // stop timeout
|
|
||||||
hRS->htim->Instance->CNT = 0;
|
|
||||||
__HAL_TIM_CLEAR_IT(hRS->htim, TIM_IT_UPDATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if((AbortMode&ABORT_RS) == 0x00)
|
if((AbortMode&ABORT_RS) == 0x00)
|
||||||
{
|
{
|
||||||
@@ -237,11 +228,11 @@ RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode)
|
|||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
//--------------------CALLBACK/HANDLER FUNCTIONS---------------------
|
//--------------------CALLBACK/HANDLER FUNCTIONS---------------------
|
||||||
/**
|
/**
|
||||||
* @brief Handle for starting receive.
|
* @brief Обработчик для начала приема.
|
||||||
* @param hRS Указатель на хендлер RS.
|
* @param hRS Указатель на хендлер RS.
|
||||||
* @param RS_msg Указатель на структуру сообщения.
|
* @param RS_msg Указатель на структуру сообщения.
|
||||||
* @return RS_RES Статус о состоянии RS после инициализации приема или окончания общения.
|
* @return RS_RES Статус о состоянии RS после инициализации приема или окончания общения.
|
||||||
* @note Определяет начинать прием команды/ответа или нет.
|
* @details Определяет начинать прием команды/ответа или нет.
|
||||||
*/
|
*/
|
||||||
RS_StatusTypeDef RS_Handle_Receive_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
|
RS_StatusTypeDef RS_Handle_Receive_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
|
||||||
{
|
{
|
||||||
@@ -249,9 +240,15 @@ RS_StatusTypeDef RS_Handle_Receive_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *R
|
|||||||
|
|
||||||
switch(hRS->sRS_Mode)
|
switch(hRS->sRS_Mode)
|
||||||
{
|
{
|
||||||
case RS_SLAVE_ALWAYS_WAIT: // in slave mode with permanent waiting
|
// В режиме мастер
|
||||||
RS_RES = RS_Receive_IT(hRS, RS_msg); break; // start receiving again
|
case RS_MASTER_REQUEST:
|
||||||
case RS_SLAVE_TIMEOUT_WAIT: // in slave mode with timeout waiting (start receiving cmd by request)
|
RS_Timeout_Start(hRS); // сразу запускаем таймаут и начинаем прием
|
||||||
|
// В режиме слейв
|
||||||
|
case RS_SLAVE_ALWAYS_WAIT:
|
||||||
|
RS_RES = RS_Receive_IT(hRS, RS_msg); // Просто запускаем фоновый прием
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RS_RESERVED:
|
||||||
RS_Set_Free(hRS); RS_RES = RS_OK; break; // end RS communication (set RS unbusy)
|
RS_Set_Free(hRS); RS_RES = RS_OK; break; // end RS communication (set RS unbusy)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,11 +260,11 @@ RS_StatusTypeDef RS_Handle_Receive_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *R
|
|||||||
return RS_RES;
|
return RS_RES;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @brief Handle for starting transmit.
|
* @brief Обработчик для начала передачи.
|
||||||
* @param hRS Указатель на хендлер RS.
|
* @param hRS Указатель на хендлер RS.
|
||||||
* @param RS_msg Указатель на структуру сообщения.
|
* @param RS_msg Указатель на структуру сообщения.
|
||||||
* @return RS_RES Статус о состоянии RS после инициализации передачи.
|
* @return RS_RES Статус о состоянии RS после инициализации передачи.
|
||||||
* @note Определяет отвечать ли на команду или нет.
|
* @details Определяет отвечать ли на команду или нет.
|
||||||
*/
|
*/
|
||||||
RS_StatusTypeDef RS_Handle_Transmit_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
|
RS_StatusTypeDef RS_Handle_Transmit_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
|
||||||
{
|
{
|
||||||
@@ -276,13 +273,14 @@ RS_StatusTypeDef RS_Handle_Transmit_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *
|
|||||||
switch(hRS->sRS_Mode)
|
switch(hRS->sRS_Mode)
|
||||||
{
|
{
|
||||||
case RS_SLAVE_ALWAYS_WAIT: // in slave mode always response
|
case RS_SLAVE_ALWAYS_WAIT: // in slave mode always response
|
||||||
case RS_SLAVE_TIMEOUT_WAIT: // transmit response
|
case RS_RESERVED: // transmit response
|
||||||
|
case RS_MASTER_REQUEST: // transmit response
|
||||||
RS_RES = RS_Transmit_IT(hRS, RS_msg); break;
|
RS_RES = RS_Transmit_IT(hRS, RS_msg); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(RS_RES != RS_OK)
|
if(RS_RES != RS_OK)
|
||||||
{
|
{
|
||||||
if(hRS->sRS_Mode < RS_MASTER_START)
|
if(hRS->sRS_Mode < RS_MASTER_MODE_START)
|
||||||
{
|
{
|
||||||
RS_Handle_Receive_Start(hRS, RS_msg);
|
RS_Handle_Receive_Start(hRS, RS_msg);
|
||||||
}
|
}
|
||||||
@@ -294,10 +292,10 @@ RS_StatusTypeDef RS_Handle_Transmit_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief UART TX Callback: define behaviour after transmiting message.
|
* @brief UART TX Callback: коллбек после окончания передачи.
|
||||||
* @param hRS Указатель на хендлер RS.
|
* @param hRS Указатель на хендлер RS.
|
||||||
* @return RS_RES Статус о состоянии RS после обработки приема.
|
* @return RS_RES Статус о состоянии RS после обработки приема.
|
||||||
* @note Определяет поведение RS после передачи сообщения.
|
* @details Определяет поведение RS после передачи сообщения.
|
||||||
*/
|
*/
|
||||||
RS_StatusTypeDef RS_UART_TxCpltCallback(RS_HandleTypeDef *hRS)
|
RS_StatusTypeDef RS_UART_TxCpltCallback(RS_HandleTypeDef *hRS)
|
||||||
{
|
{
|
||||||
@@ -306,24 +304,18 @@ RS_StatusTypeDef RS_UART_TxCpltCallback(RS_HandleTypeDef *hRS)
|
|||||||
|
|
||||||
//--------------ENDING TRANSMITTING-------------
|
//--------------ENDING TRANSMITTING-------------
|
||||||
RS_Set_TX_End(hRS);
|
RS_Set_TX_End(hRS);
|
||||||
RS_EnableReceive();
|
|
||||||
// for(int i = 0; i < hRS->sRS_Timeout; i++);
|
|
||||||
|
|
||||||
//-----------START RECEIVING or END RS----------
|
//-----------START RECEIVING or END RS----------
|
||||||
RS_RES = RS_Handle_Receive_Start(hRS, hRS->pMessagePtr);
|
RS_RES = RS_Handle_Receive_Start(hRS, hRS->pMessagePtr);
|
||||||
|
|
||||||
// if(RS_RES != RS_OK)
|
|
||||||
// {
|
|
||||||
// __NOP();
|
|
||||||
// }
|
|
||||||
return RS_RES;
|
return RS_RES;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Handler for UART.
|
* @brief Обработчик прерывания UART.
|
||||||
* @param hRS Указатель на хендлер RS.
|
* @param hRS Указатель на хендлер RS.
|
||||||
* @note Обрабатывает ошибки если есть и вызывает RS Коллбеки.
|
* @details Обрабатывает ошибки если есть и вызывает RS Коллбеки.
|
||||||
* Добавить вызов этой функции в UARTx_IRQHandler() после HAL_UART_IRQHandler().
|
* Добавить вызов этой функции в UARTx_IRQHandler() ВМЕСТО HAL_UART_IRQHandler().
|
||||||
*/
|
*/
|
||||||
void RS_UART_Handler(RS_HandleTypeDef *hRS)
|
void RS_UART_Handler(RS_HandleTypeDef *hRS)
|
||||||
{
|
{
|
||||||
@@ -331,13 +323,14 @@ void RS_UART_Handler(RS_HandleTypeDef *hRS)
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//-------------CHECK IDLE FLAG FIRST-------------
|
//-------------CHECK IDLE FLAG FIRST-------------
|
||||||
/* Проверяем флаг IDLE в первую очередь - это гарантирует обработку только после idle */
|
/* Проверяем флаг IDLE в первую очередь - это гарантирует обработку только после idle */
|
||||||
if(__HAL_UART_GET_FLAG(hRS->huart, UART_FLAG_IDLE) && __HAL_UART_GET_IT_SOURCE(hRS->huart, UART_IT_IDLE))
|
if(__HAL_UART_GET_FLAG(hRS->huart, UART_FLAG_IDLE) && __HAL_UART_GET_IT_SOURCE(hRS->huart, UART_IT_IDLE))
|
||||||
{
|
{
|
||||||
__HAL_UART_CLEAR_IDLEFLAG(hRS->huart); // Важно: очистить флаг IDLE
|
__HAL_UART_CLEAR_IDLEFLAG(hRS->huart); // Важно: очистить флаг IDLE
|
||||||
//-------------STANDARD UART HANDLING-------------
|
//-------------STANDARD UART HANDLING-------------
|
||||||
HAL_UART_IRQHandler(hRS->huart);
|
HAL_UART_IRQHandler(hRS->huart);
|
||||||
|
hRS->f.RX_Continue = 0;
|
||||||
|
|
||||||
// Если прием активен и мы получили IDLE - это конец фрейма
|
// Если прием активен и мы получили IDLE - это конец фрейма
|
||||||
if(RS_Is_RX_Busy(hRS) && hRS->f.RX_Ongoing)
|
if(RS_Is_RX_Busy(hRS) && hRS->f.RX_Ongoing)
|
||||||
@@ -356,29 +349,23 @@ void RS_UART_Handler(RS_HandleTypeDef *hRS)
|
|||||||
|
|
||||||
// Парсим наше сообщение
|
// Парсим наше сообщение
|
||||||
RS_StatusTypeDef parse_res = RS_Parse_Message(hRS, hRS->pMessagePtr, hRS->pBufferPtr);
|
RS_StatusTypeDef parse_res = RS_Parse_Message(hRS, hRS->pMessagePtr, hRS->pBufferPtr);
|
||||||
|
|
||||||
// Проверяем адрес Modbus перед обработкой
|
// Если сообещине принято корректно
|
||||||
if(hRS->pMessagePtr->MbAddr != hRS->ID)
|
if(parse_res == RS_OK)
|
||||||
{
|
{
|
||||||
// Чужое сообщение - игнорируем и начинаем новый прием
|
RS_Timeout_Stop(hRS);
|
||||||
RS_Abort(hRS, ABORT_RX);
|
|
||||||
RS_Handle_Receive_Start(hRS, hRS->pMessagePtr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Если сообещине принято корректно - отвечаем на него
|
|
||||||
if(parse_res != RS_SKIP)
|
|
||||||
{
|
|
||||||
if(hRS->htim)
|
|
||||||
{
|
|
||||||
// Останавливаем таймаут
|
|
||||||
if(hRS->sRS_Timeout)
|
|
||||||
HAL_TIM_Base_Stop_IT(hRS->htim);
|
|
||||||
}
|
|
||||||
hRS->lastPacketTick = uwTick;
|
hRS->lastPacketTick = uwTick;
|
||||||
RS_Response(hRS, hRS->pMessagePtr);
|
if(hRS->sRS_Mode < RS_MASTER_MODE_START)
|
||||||
|
RS_Response(hRS, hRS->pMessagePtr); // отвечаем на запрос
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(hRS->pCallback)
|
||||||
|
{
|
||||||
|
hRS->pCallback(hRS, hRS->pMessagePtr); // обрабатываем ответ
|
||||||
|
RS_Set_Free(hRS); // освобожднаем RS
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -399,19 +386,13 @@ void RS_UART_Handler(RS_HandleTypeDef *hRS)
|
|||||||
/* IF NO ERROR OCCURS */
|
/* IF NO ERROR OCCURS */
|
||||||
if(hRS->huart->ErrorCode == 0)
|
if(hRS->huart->ErrorCode == 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
if(hRS->htim)
|
// if first byte is received and receive is active
|
||||||
|
if((hRS->huart->RxXferCount+1 == hRS->huart->RxXferSize) && RS_Is_RX_Busy(hRS))
|
||||||
{
|
{
|
||||||
hRS->htim->Instance->CNT = 0; // reset cnt;
|
RS_Timeout_Start(hRS);
|
||||||
/* Start timeout при получении первого байта */
|
|
||||||
if(hRS->sRS_Timeout) // if timeout setted
|
|
||||||
if((hRS->huart->RxXferCount+1 == hRS->huart->RxXferSize) && RS_Is_RX_Busy(hRS)) // if first byte is received and receive is active
|
|
||||||
{
|
|
||||||
hRS->htim->Instance->ARR = hRS->sRS_Timeout;
|
|
||||||
HAL_TIM_Base_Start_IT(hRS->htim);
|
|
||||||
RS_Set_RX_Active_Flags(hRS);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
RS_Timeout_Update(hRS);
|
||||||
|
|
||||||
/* RX Callback - теперь НЕ вызываем здесь, ждем IDLE */
|
/* RX Callback - теперь НЕ вызываем здесь, ждем IDLE */
|
||||||
|
|
||||||
@@ -425,6 +406,10 @@ void RS_UART_Handler(RS_HandleTypeDef *hRS)
|
|||||||
//----------------ERRORS HANDLER----------------
|
//----------------ERRORS HANDLER----------------
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (hRS->huart->ErrorCode & HAL_UART_ERROR_ORE)
|
||||||
|
{
|
||||||
|
MB_Diagnostics_CharacterOverrunCnt(); // <-- Обнаружено переполнение
|
||||||
|
}
|
||||||
//TrackerCnt_Err(hRS->rs_err);
|
//TrackerCnt_Err(hRS->rs_err);
|
||||||
/* de-init uart transfer */
|
/* de-init uart transfer */
|
||||||
RS_Abort(hRS, ABORT_RS);
|
RS_Abort(hRS, ABORT_RS);
|
||||||
@@ -436,10 +421,10 @@ void RS_UART_Handler(RS_HandleTypeDef *hRS)
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Handler for TIM.
|
* @brief Обработчик прерывания TIM.
|
||||||
* @param hRS Указатель на хендлер RS.
|
* @param hRS Указатель на хендлер RS.
|
||||||
* @note Попадание сюда = таймаут и перезапуск RS приема
|
* @details Попадание сюда = таймаут и перезапуск RS приема
|
||||||
* Добавить вызов этой функции в TIMx_IRQHandler() после HAL_TIM_IRQHandler().
|
* Добавить вызов этой функции в TIMx_IRQHandler() ВМЕСТО HAL_TIM_IRQHandler().
|
||||||
*/
|
*/
|
||||||
void RS_TIM_Handler(RS_HandleTypeDef *hRS)
|
void RS_TIM_Handler(RS_HandleTypeDef *hRS)
|
||||||
{
|
{
|
||||||
@@ -449,13 +434,73 @@ void RS_TIM_Handler(RS_HandleTypeDef *hRS)
|
|||||||
}
|
}
|
||||||
HAL_TIM_IRQHandler(hRS->htim);
|
HAL_TIM_IRQHandler(hRS->htim);
|
||||||
|
|
||||||
RS_Abort(hRS, ABORT_RS);
|
RS_Abort(hRS, ABORT_RS);
|
||||||
|
|
||||||
if(hRS->pMessagePtr->MbAddr == hRS->ID) // ошибка если таймаут по нашему сообщению
|
if(hRS->pMessagePtr->MbAddr == hRS->ID) // ошибка если таймаут по нашему сообщению
|
||||||
TrackerCnt_Err(hRS->rs_err);
|
TrackerCnt_Err(hRS->rs_err);
|
||||||
|
|
||||||
RS_Handle_Receive_Start(hRS, hRS->pMessagePtr);
|
if(hRS->sRS_Mode == RS_MASTER_REQUEST) {
|
||||||
|
// Мастер: таймаут ответа -> освобождаем для нового запроса
|
||||||
|
RS_Set_Free(hRS);
|
||||||
|
} else {
|
||||||
|
// Слейв: перезапускаем прием
|
||||||
|
RS_Handle_Receive_Start(hRS, hRS->pMessagePtr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Запуск таймаута приема.
|
||||||
|
* @param hRS Указатель на хендлер RS.
|
||||||
|
* @return RS_RES Статус операции.
|
||||||
|
* @details Запускает таймер для отсчета времени ожидания следующего байта.
|
||||||
|
*/
|
||||||
|
RS_StatusTypeDef RS_Timeout_Start(RS_HandleTypeDef *hRS)
|
||||||
|
{
|
||||||
|
if(hRS->htim)
|
||||||
|
{
|
||||||
|
hRS->htim->Instance->CNT = 0; // reset cnt;
|
||||||
|
if(hRS->sRS_Timeout) // if timeout setted
|
||||||
|
{
|
||||||
|
hRS->htim->Instance->ARR = hRS->sRS_Timeout;
|
||||||
|
HAL_TIM_Base_Start_IT(hRS->htim);
|
||||||
|
RS_Set_RX_Active_Flags(hRS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return RS_OK;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief Остановка таймаута приема.
|
||||||
|
* @param hRS Указатель на хендлер RS.
|
||||||
|
* @return RS_RES Статус операции.
|
||||||
|
* @details Останавливает таймер ожидания.
|
||||||
|
*/
|
||||||
|
RS_StatusTypeDef RS_Timeout_Stop(RS_HandleTypeDef *hRS)
|
||||||
|
{
|
||||||
|
if(hRS->htim)
|
||||||
|
{
|
||||||
|
// Останавливаем таймаут
|
||||||
|
if(hRS->sRS_Timeout)
|
||||||
|
HAL_TIM_Base_Stop_IT(hRS->htim);
|
||||||
|
hRS->htim->Instance->CNT = 0;
|
||||||
|
__HAL_TIM_CLEAR_IT(hRS->htim, TIM_IT_UPDATE);
|
||||||
|
}
|
||||||
|
return RS_OK;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief Обновление (сброс) таймаута приема.
|
||||||
|
* @param hRS Указатель на хендлер RS.
|
||||||
|
* @return RS_RES Статус операции.
|
||||||
|
* @details Сбрасывает счетчик таймера в 0.
|
||||||
|
*/
|
||||||
|
RS_StatusTypeDef RS_Timeout_Update(RS_HandleTypeDef *hRS)
|
||||||
|
{
|
||||||
|
if(hRS->htim)
|
||||||
|
{
|
||||||
|
hRS->htim->Instance->CNT = 0; // reset cnt;
|
||||||
|
}
|
||||||
|
return RS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------CALLBACK/HANDLER FUNCTIONS---------------------
|
//--------------------CALLBACK/HANDLER FUNCTIONS---------------------
|
||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -468,7 +513,6 @@ void RS_TIM_Handler(RS_HandleTypeDef *hRS)
|
|||||||
* @param hRS Указатель на хендлер RS.
|
* @param hRS Указатель на хендлер RS.
|
||||||
* @param RS_msg Указатель на структуру сообщения.
|
* @param RS_msg Указатель на структуру сообщения.
|
||||||
* @return RS_RES Статус о результате ответа на комманду.
|
* @return RS_RES Статус о результате ответа на комманду.
|
||||||
* @note Обработка принятой комманды и ответ на неё.
|
|
||||||
*/
|
*/
|
||||||
__weak RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
|
__weak RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
|
||||||
{
|
{
|
||||||
@@ -477,12 +521,11 @@ __weak RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Собрать сообщение в буфер UART.
|
* @brief Пользовательская функция для сбора сообщения в буфер UART.
|
||||||
* @param hRS Указатель на хендлер RS.
|
* @param hRS Указатель на хендлер RS.
|
||||||
* @param RS_msg Указатель на структуру сообщения.
|
* @param RS_msg Указатель на структуру сообщения.
|
||||||
* @param msg_uart_buff Указатель на буффер UART.
|
* @param msg_uart_buff Указатель на буффер UART.
|
||||||
* @return RS_RES Статус о результате заполнения буфера.
|
* @return RS_RES Статус о результате заполнения буфера.
|
||||||
* @note Заполнение буффера UART из структуры сообщения.
|
|
||||||
*/
|
*/
|
||||||
__weak RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff)
|
__weak RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff)
|
||||||
{
|
{
|
||||||
@@ -491,12 +534,11 @@ __weak RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Разпарсить сообщение из буфера UART.
|
* @brief Пользовательская функция для парса сообщения из буфера UART.
|
||||||
* @param hRS Указатель на хендлер RS.
|
* @param hRS Указатель на хендлер RS.
|
||||||
* @param RS_msg Указатель на структуру сообщения.
|
* @param RS_msg Указатель на структуру сообщения.
|
||||||
* @param msg_uart_buff Указатель на буффер UART.
|
* @param msg_uart_buff Указатель на буффер UART.
|
||||||
* @return RS_RES Статус о результате заполнения структуры.
|
* @return RS_RES Статус о результате заполнения структуры.
|
||||||
* @note Заполнение структуры сообщения из буффера UART.
|
|
||||||
*/
|
*/
|
||||||
__weak RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff)
|
__weak RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff)
|
||||||
{
|
{
|
||||||
|
|||||||
139
README.md
139
README.md
@@ -3,7 +3,7 @@
|
|||||||
Библиотека реализует Modbus RTU Slave для STM32 с использованием HAL. Работает в прерываниях с детектированием конца фрейма по IDLE линии и таймаутами через прерывание таймера.
|
Библиотека реализует Modbus RTU Slave для STM32 с использованием HAL. Работает в прерываниях с детектированием конца фрейма по IDLE линии и таймаутами через прерывание таймера.
|
||||||
|
|
||||||
## Быстрый старт
|
## Быстрый старт
|
||||||
_Note: Здесь описано подключение просто архива c исходниками. Если надо подключить библиотеку как субмодуль: см. ветку release в этом репозитории._
|
_Note: Здесь описано подключение просто архива c исходниками. Если надо подключить библиотеку как субмодуль: см. ветку **release** в этом репозитории._
|
||||||
|
|
||||||
### 1. Настройка периферии
|
### 1. Настройка периферии
|
||||||
|
|
||||||
@@ -20,14 +20,14 @@ _Note: Здесь описано подключение просто архив
|
|||||||
|
|
||||||
void USARTx_IRQHandler(void)
|
void USARTx_IRQHandler(void)
|
||||||
{
|
{
|
||||||
RS_UART_Handler(&modbus1);
|
RS_UART_Handler(&hmodbus1);
|
||||||
return;
|
return;
|
||||||
HAL_UART_IRQHandler(&huart);
|
HAL_UART_IRQHandler(&huart);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TIMx_IRQHandler(void)
|
void TIMx_IRQHandler(void)
|
||||||
{
|
{
|
||||||
RS_TIM_Handler(&modbus1);
|
RS_TIM_Handler(&hmodbus1);
|
||||||
return;
|
return;
|
||||||
HAL_TIM_IRQHandler(&htim);
|
HAL_TIM_IRQHandler(&htim);
|
||||||
}
|
}
|
||||||
@@ -39,8 +39,8 @@ void TIMx_IRQHandler(void)
|
|||||||
|
|
||||||
```c
|
```c
|
||||||
// MODBUS PARAMS
|
// MODBUS PARAMS
|
||||||
#define MODBUS_DEVICE_ID 1 // Адрес устройства в сети Modbus
|
#define MODBUS_DEVICE_ID 1 ///< Адрес устройства в сети Modbus
|
||||||
#define MODBUS_TIMEOUT 100 // Таймаут в тиках таймера (рекомендуется 100-200ms)
|
#define MODBUS_TIMEOUT 5000 ///< Таймаут в тиках таймера
|
||||||
|
|
||||||
// Строковые идентификаторы устройства
|
// Строковые идентификаторы устройства
|
||||||
#define MODBUS_VENDOR_NAME "NIO-12"
|
#define MODBUS_VENDOR_NAME "NIO-12"
|
||||||
@@ -55,37 +55,87 @@ void TIMx_IRQHandler(void)
|
|||||||
// Периферия
|
// Периферия
|
||||||
#define mb_huart huart1 // Удобный дефайн для модбасовского UART
|
#define mb_huart huart1 // Удобный дефайн для модбасовского UART
|
||||||
#define mb_htim htim3 // Удобный дефайн для модбасовского таймера
|
#define mb_htim htim3 // Удобный дефайн для модбасовского таймера
|
||||||
|
|
||||||
|
// Модули modbus
|
||||||
|
#define MODBUS_ENABLE_SLAVE ///< Включить обработку МАСТЕР режима
|
||||||
|
//#define MODBUS_ENABLE_MASTER ///< Включить обработку СЛЕЙВ режима
|
||||||
|
|
||||||
|
#define MODBUS_ENABLE_COILS ///< Включить обработку коилов
|
||||||
|
#define MODBUS_ENABLE_HOLDINGS ///< Включить обработку регистров хранения
|
||||||
|
#define MODBUS_ENABLE_INPUTS ///< Включить обработку входных регистров
|
||||||
|
#define MODBUS_ENABLE_DEVICE_IDENTIFICATIONS ///< Включить обработку идентификаторы устройства
|
||||||
|
#define MODBUS_ENABLE_DIAGNOSTICS ///< Включить обработку диагностики модбас
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4. Инициализация в коде
|
### 4. Инициализация в коде
|
||||||
|
|
||||||
В `main()` после инициализации HAL:
|
Чтобы настроить Slave-режим `main()` после инициализации HAL:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
#include "modbus.h"
|
#include "modbus.h"
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
// Инициализация HAL
|
// Инициализация HAL
|
||||||
HAL_Init();
|
HAL_Init();
|
||||||
SystemClock_Config();
|
SystemClock_Config();
|
||||||
MX_GPIO_Init();
|
MX_GPIO_Init();
|
||||||
MX_USART1_UART_Init();
|
MX_USART1_UART_Init();
|
||||||
MX_TIM3_Init();
|
MX_TIM3_Init();
|
||||||
|
|
||||||
// Инициализация Modbus
|
// Инициализация Modbus
|
||||||
MODBUS_SetupHardware(&hmodbus1, &mb_huart, &mb_htim);
|
MODBUS_FirstInit(&hmodbus1, &mb_huart, &mb_htim);
|
||||||
|
MODBUS_Config(&hmodbus1, MODBUS_DEVICE_ID, MODBUS_TIMEOUT, MODBUS_MODE_SLAVE);
|
||||||
// Запуск приема Modbus
|
|
||||||
MODBUS_SlaveStart(&hmodbus1, &MODBUS_MSG);
|
// Запуск приема Modbus
|
||||||
|
MODBUS_SlaveStart(&hmodbus1, NULL);
|
||||||
while (1)
|
|
||||||
{
|
while (1)
|
||||||
// Основной цикл
|
{
|
||||||
}
|
// Основной цикл
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Чтобы настроить Master-режим `main()` после инициализации HAL:
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "modbus.h"
|
||||||
|
read_hold[10];
|
||||||
|
// Запрос на 1 ID, считать холдинг регистры с 0 адреса 10 штук
|
||||||
|
RS_MsgTypeDef read_hold_cmd = MB_MASTER_READ_HOLDING_REGS(1, 0, 10);
|
||||||
|
// коллбек, вызовется при получении ответа от слейва
|
||||||
|
void callback_func(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
|
||||||
|
{
|
||||||
|
// MB_RespGet_... Чтобы достать нужные данные из ответа
|
||||||
|
for(int addr = MODBUS_MSG.Addr; addr < MODBUS_MSG.Addr + MODBUS_MSG.Qnt; addr++)
|
||||||
|
{
|
||||||
|
uint16_t value;
|
||||||
|
if(MB_RespGet_RegisterValue(&MODBUS_MSG, addr, &value))
|
||||||
|
{
|
||||||
|
read_hold[i] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
// Инициализация HAL
|
||||||
|
HAL_Init();
|
||||||
|
SystemClock_Config();
|
||||||
|
MX_GPIO_Init();
|
||||||
|
MX_USART1_UART_Init();
|
||||||
|
MX_TIM3_Init();
|
||||||
|
|
||||||
|
// Инициализация Modbus
|
||||||
|
MODBUS_FirstInit(&hmodbus1, &mb_huart, &mb_htim);
|
||||||
|
MODBUS_Config(&hmodbus1, 0, MODBUS_TIMEOUT, MODBUS_MODE_MASTER);
|
||||||
|
|
||||||
|
// Запрос по Modbus
|
||||||
|
MODBUS_MasterRequest(&hmodbus1, &read_hold_cmd, &callback_func);
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
### 5. Настройка карты данных
|
### 5. Настройка карты данных
|
||||||
|
|
||||||
В `modbus_data.h` настройте регистры и coils под ваше устройство:
|
В `modbus_data.h` настройте регистры и coils под ваше устройство:
|
||||||
@@ -134,6 +184,7 @@ typedef struct
|
|||||||
|
|
||||||
### 6. Доступ к данным в коде
|
### 6. Доступ к данным в коде
|
||||||
|
|
||||||
|
В режиме слейва есть дефайны для удобного выставления Коилов. На случай если они не упакованы в битовые поля
|
||||||
```c
|
```c
|
||||||
// Чтение входных регистров
|
// Чтение входных регистров
|
||||||
uint16_t temp = MB_DATA.InRegs.Temperature;
|
uint16_t temp = MB_DATA.InRegs.Temperature;
|
||||||
@@ -142,15 +193,50 @@ uint16_t temp = MB_DATA.InRegs.Temperature;
|
|||||||
MB_DATA.HoldRegs.SetpointTemp = 2500;
|
MB_DATA.HoldRegs.SetpointTemp = 2500;
|
||||||
|
|
||||||
// Управление coils
|
// Управление coils
|
||||||
MB_Set_Coil_Local(&MB_DATA.Coils, 0); // Включить Relay1
|
MB_Coil_Set_Local(&MB_DATA.Coils, 0); // Включить Relay1
|
||||||
MB_Reset_Coil_Local(&MB_DATA.Coils, 1); // Выключить Relay2
|
MB_Coil_Reset_Local(&MB_DATA.Coils, 1); // Выключить Relay2
|
||||||
|
|
||||||
// Чтение coil
|
// Чтение coil
|
||||||
if (MB_Read_Coil_Local(&MB_DATA.Coils, 2)) {
|
if (MB_Coil_Read_Local(&MB_DATA.Coils, 2)) {
|
||||||
// Pump включен
|
// Pump включен
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
В режиме мастера есть функции для получения информации из ответа `MB_RespGet_...()`
|
||||||
|
```c
|
||||||
|
// Чтение регистров: Получить запрошенные регистры
|
||||||
|
uint16_t value;
|
||||||
|
if(MB_RespGet_RegisterValue(&MODBUS_MSG, 105, ®_value))
|
||||||
|
{
|
||||||
|
printf("Register 105 value: %d\n", reg_value);
|
||||||
|
}
|
||||||
|
// Чтение коилов: Получить запрошенные коилы
|
||||||
|
int state;
|
||||||
|
if(MB_RespGet_CoilState(&MODBUS_MSG, 25, &coil_state))
|
||||||
|
{
|
||||||
|
printf("Coil 25 state: %s\n", coil_state ? "ON" : "OFF");
|
||||||
|
}
|
||||||
|
// Чтение диагностики: Получить запрошенныую диагностику
|
||||||
|
uint16_t counter_value;
|
||||||
|
if(MB_RespGet_DiagnosticResponse(&MODBUS_MSG, &counter_value))
|
||||||
|
{
|
||||||
|
printf("Counter value: %d\n", counter_value);
|
||||||
|
}
|
||||||
|
// Чтение идентификаторов: Получить запрошенные идентификаторы
|
||||||
|
uint8_t length;
|
||||||
|
char vendor_name[64];
|
||||||
|
if(MB_RespGet_ObjectById(&MODBUS_MSG, 0x00, vendor_name, &length))
|
||||||
|
{
|
||||||
|
printf("Vendor Name: %s (length: %d)\n", vendor_name, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t obj_id, obj_length;
|
||||||
|
char obj_data[64];
|
||||||
|
if(MB_RespGet_ObjectByIndex(&MODBUS_MSG, 0x00, &obj_id, obj_data, &obj_length))
|
||||||
|
{
|
||||||
|
printf("First object - ID: 0x%02X, Data: %s\n", obj_id, obj_data);
|
||||||
|
}
|
||||||
|
```
|
||||||
## Поддерживаемые функции Modbus
|
## Поддерживаемые функции Modbus
|
||||||
|
|
||||||
| Функция | Код | Описание |
|
| Функция | Код | Описание |
|
||||||
@@ -160,6 +246,7 @@ if (MB_Read_Coil_Local(&MB_DATA.Coils, 2)) {
|
|||||||
| Read Holding Registers | 0x03 | Чтение регистров хранения |
|
| Read Holding Registers | 0x03 | Чтение регистров хранения |
|
||||||
| Write Single Coil | 0x05 | Запись одиночного coil |
|
| Write Single Coil | 0x05 | Запись одиночного coil |
|
||||||
| Write Single Register | 0x06 | Запись одиночного регистра |
|
| Write Single Register | 0x06 | Запись одиночного регистра |
|
||||||
|
| Diagnostics (Serial Line only) | 0x08 | Чтение диагностически и управление режимом работы |
|
||||||
| Write Multiple Coils | 0x0F | Запись множественных coils |
|
| Write Multiple Coils | 0x0F | Запись множественных coils |
|
||||||
| Write Multiple Registers | 0x10 | Запись множественных регистров |
|
| Write Multiple Registers | 0x10 | Запись множественных регистров |
|
||||||
| Read Device Identification | 0x2B | Чтение идентификации устройства |
|
| Read Device Identification | 0x2B | Чтение идентификации устройства |
|
||||||
|
|||||||
@@ -56,7 +56,16 @@ void SystemClock_Config(void);
|
|||||||
|
|
||||||
/* Private user code ---------------------------------------------------------*/
|
/* Private user code ---------------------------------------------------------*/
|
||||||
/* USER CODE BEGIN 0 */
|
/* USER CODE BEGIN 0 */
|
||||||
|
int coil_to_toggle = 0;
|
||||||
|
int coil_state = 0;
|
||||||
|
int coil_real_state = 0;
|
||||||
|
void master_callback(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *msg)
|
||||||
|
{
|
||||||
|
if(MB_RespGet_CoilState(msg, coil_to_toggle, &coil_real_state))
|
||||||
|
{
|
||||||
|
coil_state = coil_real_state;
|
||||||
|
}
|
||||||
|
}
|
||||||
/* USER CODE END 0 */
|
/* USER CODE END 0 */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -91,14 +100,27 @@ int main(void)
|
|||||||
MX_USART1_UART_Init();
|
MX_USART1_UART_Init();
|
||||||
MX_TIM3_Init();
|
MX_TIM3_Init();
|
||||||
/* USER CODE BEGIN 2 */
|
/* USER CODE BEGIN 2 */
|
||||||
MODBUS_SetupHardware(&hmodbus1, &huart1, &htim3);
|
MODBUS_FirstInit(&hmodbus1, &huart1, &htim3);
|
||||||
RS_Receive_IT(&hmodbus1, &MODBUS_MSG);
|
#ifdef MODBUS_MODE_MASTER
|
||||||
|
MODBUS_Config(&hmodbus1, 0, MODBUS_TIMEOUT, MODBUS_MODE_MASTER);
|
||||||
|
#else
|
||||||
|
MODBUS_Config(&hmodbus1, MODBUS_DEVICE_ID, MODBUS_TIMEOUT, MODBUS_MODE_SLAVE);
|
||||||
|
MODBUS_SlaveStart(&hmodbus1, NULL);
|
||||||
|
#endif
|
||||||
/* USER CODE END 2 */
|
/* USER CODE END 2 */
|
||||||
|
|
||||||
/* Infinite loop */
|
/* Infinite loop */
|
||||||
/* USER CODE BEGIN WHILE */
|
/* USER CODE BEGIN WHILE */
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
|
#ifdef MODBUS_MODE_MASTER
|
||||||
|
HAL_Delay(1000);
|
||||||
|
MODBUS_MSG = MB_REQUEST_READ_COILS(1, 0, 5);
|
||||||
|
MODBUS_MasterRequest(&hmodbus1, &MODBUS_MSG, &master_callback);
|
||||||
|
HAL_Delay(1000);
|
||||||
|
MODBUS_MSG = MB_REQUEST_WRITE_SINGLE_COIL(1, coil_to_toggle, !coil_state);
|
||||||
|
MODBUS_MasterRequest(&hmodbus1, &MODBUS_MSG, &master_callback);
|
||||||
|
#endif
|
||||||
/* USER CODE END WHILE */
|
/* USER CODE END WHILE */
|
||||||
|
|
||||||
/* USER CODE BEGIN 3 */
|
/* USER CODE BEGIN 3 */
|
||||||
|
|||||||
3862
STM32F103_Example/MDK-ARM/Modbus_example.uvguix.wot89
Normal file
3862
STM32F103_Example/MDK-ARM/Modbus_example.uvguix.wot89
Normal file
File diff suppressed because one or more lines are too long
@@ -145,27 +145,10 @@
|
|||||||
<SetRegEntry>
|
<SetRegEntry>
|
||||||
<Number>0</Number>
|
<Number>0</Number>
|
||||||
<Key>ST-LINKIII-KEIL_SWO</Key>
|
<Key>ST-LINKIII-KEIL_SWO</Key>
|
||||||
<Name>-U005600373433510237363934 -O2254 -SF10000 -C0 -A0 -I0 -HNlocalhost -HP7184 -P1 -N00("ARM CoreSight SW-DP (ARM Core") -D00(1BA01477) -L00(0) -TO131123 -TC8000000 -TT10000000 -TP21 -TDS8000 -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -FO7 -FD20000000 -FC800 -FN1 -FF0STM32F10x_128.FLM -FS08000000 -FL010000 -FP0($$Device:STM32F103C8$Flash\STM32F10x_128.FLM) -WA0 -WE0 -WVCE4 -WS2710 -WM0 -WP2</Name>
|
<Name>-U005600373433510237363934 -O2254 -SF10000 -C0 -A0 -I0 -HNlocalhost -HP7184 -P1 -N00("ARM CoreSight SW-DP (ARM Core") -D00(2BA01477) -L00(0) -TO131123 -TC8000000 -TT10000000 -TP21 -TDS8003 -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -FO7 -FD20000000 -FC800 -FN1 -FF0STM32F10x_128.FLM -FS08000000 -FL010000 -FP0($$Device:STM32F103C8$Flash\STM32F10x_128.FLM) -WA0 -WE0 -WVCE4 -WS2710 -WM0 -WP2</Name>
|
||||||
</SetRegEntry>
|
</SetRegEntry>
|
||||||
</TargetDriverDllRegistry>
|
</TargetDriverDllRegistry>
|
||||||
<Breakpoint>
|
<Breakpoint/>
|
||||||
<Bp>
|
|
||||||
<Number>0</Number>
|
|
||||||
<Type>0</Type>
|
|
||||||
<LineNumber>227</LineNumber>
|
|
||||||
<EnabledFlag>1</EnabledFlag>
|
|
||||||
<Address>134230452</Address>
|
|
||||||
<ByteObject>0</ByteObject>
|
|
||||||
<HtxType>0</HtxType>
|
|
||||||
<ManyObjects>0</ManyObjects>
|
|
||||||
<SizeOfObject>0</SizeOfObject>
|
|
||||||
<BreakByAccess>0</BreakByAccess>
|
|
||||||
<BreakIfRCount>1</BreakIfRCount>
|
|
||||||
<Filename>E:\.WORK\STM32\STM32_Modbus\Modbus\modbus.c</Filename>
|
|
||||||
<ExecCommand></ExecCommand>
|
|
||||||
<Expression>\\Modbus_example\../../Modbus/modbus.c\227</Expression>
|
|
||||||
</Bp>
|
|
||||||
</Breakpoint>
|
|
||||||
<WatchWindow1>
|
<WatchWindow1>
|
||||||
<Ww>
|
<Ww>
|
||||||
<count>0</count>
|
<count>0</count>
|
||||||
@@ -175,7 +158,52 @@
|
|||||||
<Ww>
|
<Ww>
|
||||||
<count>1</count>
|
<count>1</count>
|
||||||
<WinNumber>1</WinNumber>
|
<WinNumber>1</WinNumber>
|
||||||
<ItemText>RS_Buffer</ItemText>
|
<ItemText>RS_Buffer,0x10</ItemText>
|
||||||
|
</Ww>
|
||||||
|
<Ww>
|
||||||
|
<count>2</count>
|
||||||
|
<WinNumber>1</WinNumber>
|
||||||
|
<ItemText>MODBUS_MSG,0x10</ItemText>
|
||||||
|
</Ww>
|
||||||
|
<Ww>
|
||||||
|
<count>3</count>
|
||||||
|
<WinNumber>1</WinNumber>
|
||||||
|
<ItemText>coil_to_toggle</ItemText>
|
||||||
|
</Ww>
|
||||||
|
<Ww>
|
||||||
|
<count>4</count>
|
||||||
|
<WinNumber>1</WinNumber>
|
||||||
|
<ItemText>coil_real_state</ItemText>
|
||||||
|
</Ww>
|
||||||
|
<Ww>
|
||||||
|
<count>5</count>
|
||||||
|
<WinNumber>1</WinNumber>
|
||||||
|
<ItemText>(uint8_t *)modbus_msg->DATA</ItemText>
|
||||||
|
</Ww>
|
||||||
|
<Ww>
|
||||||
|
<count>6</count>
|
||||||
|
<WinNumber>1</WinNumber>
|
||||||
|
<ItemText>coil_word >> (bit_index+8)</ItemText>
|
||||||
|
</Ww>
|
||||||
|
<Ww>
|
||||||
|
<count>7</count>
|
||||||
|
<WinNumber>1</WinNumber>
|
||||||
|
<ItemText>bit_index+8,0x0A</ItemText>
|
||||||
|
</Ww>
|
||||||
|
<Ww>
|
||||||
|
<count>8</count>
|
||||||
|
<WinNumber>1</WinNumber>
|
||||||
|
<ItemText>modbus_uart_buff[ind]</ItemText>
|
||||||
|
</Ww>
|
||||||
|
<Ww>
|
||||||
|
<count>9</count>
|
||||||
|
<WinNumber>1</WinNumber>
|
||||||
|
<ItemText>msg</ItemText>
|
||||||
|
</Ww>
|
||||||
|
<Ww>
|
||||||
|
<count>10</count>
|
||||||
|
<WinNumber>1</WinNumber>
|
||||||
|
<ItemText>MODBUS_MSG.DATA[0]</ItemText>
|
||||||
</Ww>
|
</Ww>
|
||||||
</WatchWindow1>
|
</WatchWindow1>
|
||||||
<WatchWindow2>
|
<WatchWindow2>
|
||||||
@@ -227,20 +255,6 @@
|
|||||||
<pszMrulep></pszMrulep>
|
<pszMrulep></pszMrulep>
|
||||||
<pSingCmdsp></pSingCmdsp>
|
<pSingCmdsp></pSingCmdsp>
|
||||||
<pMultCmdsp></pMultCmdsp>
|
<pMultCmdsp></pMultCmdsp>
|
||||||
<SystemViewers>
|
|
||||||
<Entry>
|
|
||||||
<Name>System Viewer\DBG</Name>
|
|
||||||
<WinId>35903</WinId>
|
|
||||||
</Entry>
|
|
||||||
<Entry>
|
|
||||||
<Name>System Viewer\TIM3</Name>
|
|
||||||
<WinId>35904</WinId>
|
|
||||||
</Entry>
|
|
||||||
<Entry>
|
|
||||||
<Name>System Viewer\USART1</Name>
|
|
||||||
<WinId>35905</WinId>
|
|
||||||
</Entry>
|
|
||||||
</SystemViewers>
|
|
||||||
<DebugDescription>
|
<DebugDescription>
|
||||||
<Enable>1</Enable>
|
<Enable>1</Enable>
|
||||||
<EnableFlashSeq>0</EnableFlashSeq>
|
<EnableFlashSeq>0</EnableFlashSeq>
|
||||||
@@ -556,114 +570,6 @@
|
|||||||
<File>
|
<File>
|
||||||
<GroupNumber>5</GroupNumber>
|
<GroupNumber>5</GroupNumber>
|
||||||
<FileNumber>23</FileNumber>
|
<FileNumber>23</FileNumber>
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>..\..\Modbus\Src\__crc_algs.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>__crc_algs.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>5</GroupNumber>
|
|
||||||
<FileNumber>24</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>..\..\Modbus\Src\modbus.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>modbus.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>5</GroupNumber>
|
|
||||||
<FileNumber>25</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>..\..\Modbus\Src\modbus_coils.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>modbus_coils.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>5</GroupNumber>
|
|
||||||
<FileNumber>26</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>..\..\Modbus\Src\modbus_core.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>modbus_core.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>5</GroupNumber>
|
|
||||||
<FileNumber>27</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>..\..\Modbus\Src\modbus_data.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>modbus_data.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>5</GroupNumber>
|
|
||||||
<FileNumber>28</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>..\..\Modbus\Src\modbus_devid.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>modbus_devid.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>5</GroupNumber>
|
|
||||||
<FileNumber>29</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>..\..\Modbus\Src\modbus_holdregs.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>modbus_holdregs.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>5</GroupNumber>
|
|
||||||
<FileNumber>30</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>..\..\Modbus\Src\modbus_inputregs.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>modbus_inputregs.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>5</GroupNumber>
|
|
||||||
<FileNumber>31</FileNumber>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<tvExp>0</tvExp>
|
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
|
||||||
<bDave2>0</bDave2>
|
|
||||||
<PathWithFileName>..\..\Modbus\Src\rs_message.c</PathWithFileName>
|
|
||||||
<FilenameWithoutPath>rs_message.c</FilenameWithoutPath>
|
|
||||||
<RteFlg>0</RteFlg>
|
|
||||||
<bShared>0</bShared>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<GroupNumber>5</GroupNumber>
|
|
||||||
<FileNumber>32</FileNumber>
|
|
||||||
<FileType>5</FileType>
|
<FileType>5</FileType>
|
||||||
<tvExp>0</tvExp>
|
<tvExp>0</tvExp>
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
<tvExpOptDlg>0</tvExpOptDlg>
|
||||||
@@ -675,7 +581,19 @@
|
|||||||
</File>
|
</File>
|
||||||
<File>
|
<File>
|
||||||
<GroupNumber>5</GroupNumber>
|
<GroupNumber>5</GroupNumber>
|
||||||
<FileNumber>33</FileNumber>
|
<FileNumber>24</FileNumber>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<tvExp>0</tvExp>
|
||||||
|
<tvExpOptDlg>0</tvExpOptDlg>
|
||||||
|
<bDave2>0</bDave2>
|
||||||
|
<PathWithFileName>..\..\Modbus\Src\modbus_data.c</PathWithFileName>
|
||||||
|
<FilenameWithoutPath>modbus_data.c</FilenameWithoutPath>
|
||||||
|
<RteFlg>0</RteFlg>
|
||||||
|
<bShared>0</bShared>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<GroupNumber>5</GroupNumber>
|
||||||
|
<FileNumber>25</FileNumber>
|
||||||
<FileType>5</FileType>
|
<FileType>5</FileType>
|
||||||
<tvExp>0</tvExp>
|
<tvExp>0</tvExp>
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
<tvExpOptDlg>0</tvExpOptDlg>
|
||||||
@@ -685,6 +603,138 @@
|
|||||||
<RteFlg>0</RteFlg>
|
<RteFlg>0</RteFlg>
|
||||||
<bShared>0</bShared>
|
<bShared>0</bShared>
|
||||||
</File>
|
</File>
|
||||||
|
<File>
|
||||||
|
<GroupNumber>5</GroupNumber>
|
||||||
|
<FileNumber>26</FileNumber>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<tvExp>0</tvExp>
|
||||||
|
<tvExpOptDlg>0</tvExpOptDlg>
|
||||||
|
<bDave2>0</bDave2>
|
||||||
|
<PathWithFileName>..\..\Modbus\Src\modbus.c</PathWithFileName>
|
||||||
|
<FilenameWithoutPath>modbus.c</FilenameWithoutPath>
|
||||||
|
<RteFlg>0</RteFlg>
|
||||||
|
<bShared>0</bShared>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<GroupNumber>5</GroupNumber>
|
||||||
|
<FileNumber>27</FileNumber>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<tvExp>0</tvExp>
|
||||||
|
<tvExpOptDlg>0</tvExpOptDlg>
|
||||||
|
<bDave2>0</bDave2>
|
||||||
|
<PathWithFileName>..\..\Modbus\Src\modbus_master.c</PathWithFileName>
|
||||||
|
<FilenameWithoutPath>modbus_master.c</FilenameWithoutPath>
|
||||||
|
<RteFlg>0</RteFlg>
|
||||||
|
<bShared>0</bShared>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<GroupNumber>5</GroupNumber>
|
||||||
|
<FileNumber>28</FileNumber>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<tvExp>0</tvExp>
|
||||||
|
<tvExpOptDlg>0</tvExpOptDlg>
|
||||||
|
<bDave2>0</bDave2>
|
||||||
|
<PathWithFileName>..\..\Modbus\Src\modbus_slave.c</PathWithFileName>
|
||||||
|
<FilenameWithoutPath>modbus_slave.c</FilenameWithoutPath>
|
||||||
|
<RteFlg>0</RteFlg>
|
||||||
|
<bShared>0</bShared>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<GroupNumber>5</GroupNumber>
|
||||||
|
<FileNumber>29</FileNumber>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<tvExp>0</tvExp>
|
||||||
|
<tvExpOptDlg>0</tvExpOptDlg>
|
||||||
|
<bDave2>0</bDave2>
|
||||||
|
<PathWithFileName>..\..\Modbus\Src\modbus_coils.c</PathWithFileName>
|
||||||
|
<FilenameWithoutPath>modbus_coils.c</FilenameWithoutPath>
|
||||||
|
<RteFlg>0</RteFlg>
|
||||||
|
<bShared>0</bShared>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<GroupNumber>5</GroupNumber>
|
||||||
|
<FileNumber>30</FileNumber>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<tvExp>0</tvExp>
|
||||||
|
<tvExpOptDlg>0</tvExpOptDlg>
|
||||||
|
<bDave2>0</bDave2>
|
||||||
|
<PathWithFileName>..\..\Modbus\Src\modbus_core.c</PathWithFileName>
|
||||||
|
<FilenameWithoutPath>modbus_core.c</FilenameWithoutPath>
|
||||||
|
<RteFlg>0</RteFlg>
|
||||||
|
<bShared>0</bShared>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<GroupNumber>5</GroupNumber>
|
||||||
|
<FileNumber>31</FileNumber>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<tvExp>0</tvExp>
|
||||||
|
<tvExpOptDlg>0</tvExpOptDlg>
|
||||||
|
<bDave2>0</bDave2>
|
||||||
|
<PathWithFileName>..\..\Modbus\Src\modbus_holdregs.c</PathWithFileName>
|
||||||
|
<FilenameWithoutPath>modbus_holdregs.c</FilenameWithoutPath>
|
||||||
|
<RteFlg>0</RteFlg>
|
||||||
|
<bShared>0</bShared>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<GroupNumber>5</GroupNumber>
|
||||||
|
<FileNumber>32</FileNumber>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<tvExp>0</tvExp>
|
||||||
|
<tvExpOptDlg>0</tvExpOptDlg>
|
||||||
|
<bDave2>0</bDave2>
|
||||||
|
<PathWithFileName>..\..\Modbus\Src\modbus_inputregs.c</PathWithFileName>
|
||||||
|
<FilenameWithoutPath>modbus_inputregs.c</FilenameWithoutPath>
|
||||||
|
<RteFlg>0</RteFlg>
|
||||||
|
<bShared>0</bShared>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<GroupNumber>5</GroupNumber>
|
||||||
|
<FileNumber>33</FileNumber>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<tvExp>0</tvExp>
|
||||||
|
<tvExpOptDlg>0</tvExpOptDlg>
|
||||||
|
<bDave2>0</bDave2>
|
||||||
|
<PathWithFileName>..\..\Modbus\Src\modbus_devid.c</PathWithFileName>
|
||||||
|
<FilenameWithoutPath>modbus_devid.c</FilenameWithoutPath>
|
||||||
|
<RteFlg>0</RteFlg>
|
||||||
|
<bShared>0</bShared>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<GroupNumber>5</GroupNumber>
|
||||||
|
<FileNumber>34</FileNumber>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<tvExp>0</tvExp>
|
||||||
|
<tvExpOptDlg>0</tvExpOptDlg>
|
||||||
|
<bDave2>0</bDave2>
|
||||||
|
<PathWithFileName>..\..\Modbus\Src\modbus_diag.c</PathWithFileName>
|
||||||
|
<FilenameWithoutPath>modbus_diag.c</FilenameWithoutPath>
|
||||||
|
<RteFlg>0</RteFlg>
|
||||||
|
<bShared>0</bShared>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<GroupNumber>5</GroupNumber>
|
||||||
|
<FileNumber>35</FileNumber>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<tvExp>0</tvExp>
|
||||||
|
<tvExpOptDlg>0</tvExpOptDlg>
|
||||||
|
<bDave2>0</bDave2>
|
||||||
|
<PathWithFileName>..\..\Modbus\Src\rs_message.c</PathWithFileName>
|
||||||
|
<FilenameWithoutPath>rs_message.c</FilenameWithoutPath>
|
||||||
|
<RteFlg>0</RteFlg>
|
||||||
|
<bShared>0</bShared>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<GroupNumber>5</GroupNumber>
|
||||||
|
<FileNumber>36</FileNumber>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<tvExp>0</tvExp>
|
||||||
|
<tvExpOptDlg>0</tvExpOptDlg>
|
||||||
|
<bDave2>0</bDave2>
|
||||||
|
<PathWithFileName>..\..\Modbus\Src\__crc_algs.c</PathWithFileName>
|
||||||
|
<FilenameWithoutPath>__crc_algs.c</FilenameWithoutPath>
|
||||||
|
<RteFlg>0</RteFlg>
|
||||||
|
<bShared>0</bShared>
|
||||||
|
</File>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
<Group>
|
<Group>
|
||||||
|
|||||||
@@ -567,15 +567,35 @@
|
|||||||
<GroupName>Modbus</GroupName>
|
<GroupName>Modbus</GroupName>
|
||||||
<Files>
|
<Files>
|
||||||
<File>
|
<File>
|
||||||
<FileName>__crc_algs.c</FileName>
|
<FileName>modbus_config.h</FileName>
|
||||||
|
<FileType>5</FileType>
|
||||||
|
<FilePath>..\..\Modbus\Inc\modbus_config.h</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>modbus_data.c</FileName>
|
||||||
<FileType>1</FileType>
|
<FileType>1</FileType>
|
||||||
<FilePath>..\..\Modbus\Src\__crc_algs.c</FilePath>
|
<FilePath>..\..\Modbus\Src\modbus_data.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>modbus_data.h</FileName>
|
||||||
|
<FileType>5</FileType>
|
||||||
|
<FilePath>..\..\Modbus\Inc\modbus_data.h</FilePath>
|
||||||
</File>
|
</File>
|
||||||
<File>
|
<File>
|
||||||
<FileName>modbus.c</FileName>
|
<FileName>modbus.c</FileName>
|
||||||
<FileType>1</FileType>
|
<FileType>1</FileType>
|
||||||
<FilePath>..\..\Modbus\Src\modbus.c</FilePath>
|
<FilePath>..\..\Modbus\Src\modbus.c</FilePath>
|
||||||
</File>
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>modbus_master.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\..\Modbus\Src\modbus_master.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>modbus_slave.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\..\Modbus\Src\modbus_slave.c</FilePath>
|
||||||
|
</File>
|
||||||
<File>
|
<File>
|
||||||
<FileName>modbus_coils.c</FileName>
|
<FileName>modbus_coils.c</FileName>
|
||||||
<FileType>1</FileType>
|
<FileType>1</FileType>
|
||||||
@@ -586,16 +606,6 @@
|
|||||||
<FileType>1</FileType>
|
<FileType>1</FileType>
|
||||||
<FilePath>..\..\Modbus\Src\modbus_core.c</FilePath>
|
<FilePath>..\..\Modbus\Src\modbus_core.c</FilePath>
|
||||||
</File>
|
</File>
|
||||||
<File>
|
|
||||||
<FileName>modbus_data.c</FileName>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<FilePath>..\..\Modbus\Src\modbus_data.c</FilePath>
|
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<FileName>modbus_devid.c</FileName>
|
|
||||||
<FileType>1</FileType>
|
|
||||||
<FilePath>..\..\Modbus\Src\modbus_devid.c</FilePath>
|
|
||||||
</File>
|
|
||||||
<File>
|
<File>
|
||||||
<FileName>modbus_holdregs.c</FileName>
|
<FileName>modbus_holdregs.c</FileName>
|
||||||
<FileType>1</FileType>
|
<FileType>1</FileType>
|
||||||
@@ -606,20 +616,25 @@
|
|||||||
<FileType>1</FileType>
|
<FileType>1</FileType>
|
||||||
<FilePath>..\..\Modbus\Src\modbus_inputregs.c</FilePath>
|
<FilePath>..\..\Modbus\Src\modbus_inputregs.c</FilePath>
|
||||||
</File>
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>modbus_devid.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\..\Modbus\Src\modbus_devid.c</FilePath>
|
||||||
|
</File>
|
||||||
|
<File>
|
||||||
|
<FileName>modbus_diag.c</FileName>
|
||||||
|
<FileType>1</FileType>
|
||||||
|
<FilePath>..\..\Modbus\Src\modbus_diag.c</FilePath>
|
||||||
|
</File>
|
||||||
<File>
|
<File>
|
||||||
<FileName>rs_message.c</FileName>
|
<FileName>rs_message.c</FileName>
|
||||||
<FileType>1</FileType>
|
<FileType>1</FileType>
|
||||||
<FilePath>..\..\Modbus\Src\rs_message.c</FilePath>
|
<FilePath>..\..\Modbus\Src\rs_message.c</FilePath>
|
||||||
</File>
|
</File>
|
||||||
<File>
|
<File>
|
||||||
<FileName>modbus_config.h</FileName>
|
<FileName>__crc_algs.c</FileName>
|
||||||
<FileType>5</FileType>
|
<FileType>1</FileType>
|
||||||
<FilePath>..\..\Modbus\Inc\modbus_config.h</FilePath>
|
<FilePath>..\..\Modbus\Src\__crc_algs.c</FilePath>
|
||||||
</File>
|
|
||||||
<File>
|
|
||||||
<FileName>modbus_data.h</FileName>
|
|
||||||
<FileType>5</FileType>
|
|
||||||
<FilePath>..\..\Modbus\Inc\modbus_data.h</FilePath>
|
|
||||||
</File>
|
</File>
|
||||||
</Files>
|
</Files>
|
||||||
</Group>
|
</Group>
|
||||||
|
|||||||
Reference in New Issue
Block a user