8 Commits

Author SHA1 Message Date
Razvalyaev
7d40b019fb release 0.51
Бета добавление новых кодов исключения

Улучшение механики ответа с задержкой, когда время ответа определяется пользователем, а не в прерывании сразу
2026-02-20 16:39:15 +03:00
ca8fa259c8 Обновить README.md 2026-02-20 11:26:15 +03:00
36db3964ea Обновить README.md 2026-02-20 10:48:10 +03:00
Razvalyaev
a880f46a56 release 0.5 (*API CHANGED)
- чуть переделаны некоторые дефайны для универсализации
- смена направления сделана через указател на функцию, а не глобальный дефайн
- добавлен бета осцилограф модбас
- некоторый рефакторинг
2026-02-20 10:41:31 +03:00
Razvalyaev
3aa279736d Минор фикс rs_message 2025-11-07 22:38:40 +03:00
Razvalyaev
cba13802b1 Добавление совместимости с старым API 2025-11-06 22:36:21 +03:00
Razvalyaev
c648a605f5 release 0.4 (*API CHANGED)
*Не совсем апи, но поменялись enum в modbus_core.h:
- MB_ExceptionTypeDef
- MB_FunctonTypeDef

Необходимо обновить modbus_data.c:
NO_ERRORS 		->	NO_ERRORS
ILLEGAL_FUNCTION	->	ET_ILLEGAL_FUNCTION
ILLEGAL_DATA_ADDRESS 	-> 	ET_ILLEGAL_DATA_ADDRESS
ILLEGAL_DATA_ADDRESS	->	ET_ILLEGAL_DATA_ADDRESS

- множественные правки докумнтации
- множественный рефакторинг
2025-11-06 21:33:08 +03:00
Razvalyaev
3d106f18ef release 0.3.2 Фиксы:
- Data Access API расширено функциями для чтения/записи регистров
- API для реквестов MB_RespGet.. перенесено в modbus_master
- Мастер: коллбек реквеста вызывается и при таймауте
	- В коллбеке можно понять статус реквеста по hmodbus->RS_STATUS
2025-11-05 16:38:38 +03:00
28 changed files with 2198 additions and 1318 deletions

168
Inc/__modbus_compat.h Normal file
View File

@@ -0,0 +1,168 @@
/**
*******************************************************************************
* @file __modbus_compat.h
* @brief Модуль для совместимости библиотеки MODBUS.
*******************************************************************************
* @details Файл содержит API старых функций, а также заглушки для отключенных модулей:
******************************************************************************/
#ifndef __MODBUS_COMPAT_H_
#define __MODBUS_COMPAT_H_
#include "modbus_core.h"
#define CREATE_DEPRECATED_ALIAS(old_name, new_name, type) \
__attribute__((deprecated("Use " #new_name " instead"))) \
static const type old_name = new_name;
// Для функций
#define CREATE_DEPRECATED_FUNCTION(old_name, new_name, return_type, ...) \
__attribute__((deprecated("Use " #new_name " instead"))) \
return_type old_name(__VA_ARGS__) { \
return new_name(__VA_ARGS__); \
}
/** @addtogroup MODBUS_LEGACY_API Legacy API
* @ingroup MODBUS_FUNCTIONS
* @brief Старые API функций, сохранённые для обратной совместимости.
* @note Не используйте эти функции в новом коде. Они будут удалены в будущих версиях.
* Вместо них используйте актуальные API, приведенные в втором столбце.
* @{
*/
// Устаревшие enum //Старый замените на // Новый
// | // |
// v // v
CREATE_DEPRECATED_ALIAS(NO_ERRORS, ET_NO_ERRORS, MB_ExceptionTypeDef);
CREATE_DEPRECATED_ALIAS(ILLEGAL_FUNCTION, ET_ILLEGAL_FUNCTION, MB_ExceptionTypeDef);
CREATE_DEPRECATED_ALIAS(ILLEGAL_DATA_ADDRESS, ET_ILLEGAL_DATA_ADDRESS, MB_ExceptionTypeDef);
CREATE_DEPRECATED_ALIAS(ILLEGAL_DATA_VALUE, ET_ILLEGAL_DATA_VALUE, MB_ExceptionTypeDef);
CREATE_DEPRECATED_ALIAS(SLAVE_DEVICE_FAILURE, ET_SLAVE_DEVICE_FAILURE, MB_ExceptionTypeDef);
CREATE_DEPRECATED_ALIAS(MB_R_COILS, FC_R_COILS, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_R_DISC_IN, FC_R_DISC_IN, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_R_HOLD_REGS, FC_R_HOLD_REGS, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_R_IN_REGS, FC_R_IN_REGS, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_W_COIL, FC_W_COIL, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_W_HOLD_REG, FC_W_HOLD_REG, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_W_COILS, FC_W_COILS, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_W_HOLD_REGS, FC_W_HOLD_REGS, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_R_DIAGNOSTICS, FC_R_DIAGNOSTICS, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_R_DEVICE_ID, FC_R_DEVICE_ID, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_ERR_R_COILS, FC_ERR_R_COILS, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_ERR_R_DISC_IN, FC_ERR_R_DISC_IN, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_ERR_R_IN_REGS, FC_ERR_R_IN_REGS, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_ERR_R_HOLD_REGS, FC_ERR_R_HOLD_REGS, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_ERR_W_COIL, FC_ERR_W_COIL, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_ERR_W_HOLD_REG, FC_ERR_W_HOLD_REG, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_ERR_W_COILS, FC_ERR_W_COILS, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_ERR_W_HOLD_REGS, FC_ERR_W_HOLD_REGS, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_ERR_R_DIAGNOSTIC, FC_ERR_R_DIAGNOSTIC, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_ERR_R_DEVICE_INFO, FC_ERR_R_DEVICE_INFO, MB_FunctonTypeDef);
CREATE_DEPRECATED_ALIAS(MB_BASIC_IDENTIFICATIONS, RID_BASIC_IDENTIFICATIONS, MB_ReadDevId);
CREATE_DEPRECATED_ALIAS(MB_REGULAR_IDENTIFICATIONS, RID_REGULAR_IDENTIFICATIONS, MB_ReadDevId);
CREATE_DEPRECATED_ALIAS(MB_EXTENDED_IDENTIFICATIONS, RID_EXTENDED_IDENTIFICATIONS, MB_ReadDevId);
CREATE_DEPRECATED_ALIAS(MB_SPEDIFIC_IDENTIFICATIONS, RID_SPEDIFIC_IDENTIFICATIONS, MB_ReadDevId);
#define MbAddr DeviceAddr
/** MODBUS_LEGACY_API
* @}
*/
/** @cond Заглушки отключенных модулей */
#ifndef MODBUS_ENABLE_COILS
#define MB_Coil_Write_Global(Addr, WriteVal) ET_ILLEGAL_FUNCTION
#define MB_Coil_Read_Global(Addr, Exception) 0
#define MB_Process_Read_Coils(modbus_msg) 0
#define MB_Process_Write_Single_Coil(modbus_msg) 0
#define MB_Process_Write_Miltuple_Coils(modbus_msg) 0
#endif
#ifndef MODBUS_ENABLE_HOLDINGS
#define MB_Holding_Write_Global(Addr, WriteVal) ET_ILLEGAL_FUNCTION
#define MB_Holding_Read_Global(Addr, Exception) 0
#define MB_Process_Read_Hold_Regs(modbus_msg) 0
#define MB_Process_Write_Single_Reg(modbus_msg) 0
#define MB_Process_Write_Miltuple_Regs(modbus_msg) 0
#endif
#ifndef MODBUS_ENABLE_INPUTS
#define MB_Input_Write_Global(Addr, WriteVal) ET_ILLEGAL_FUNCTION
#define MB_Input_Read_Global(Addr, Exception) 0
#define MB_Process_Read_Input_Regs(modbus_msg) 0
#endif
#ifndef MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
#define MB_WriteSingleObjectToMessage(mbdata, ind, obj)
#define MB_WriteObjectsToMessage(modbus_msg, maxidofobj)
#define MB_Process_Read_Device_Identifications(modbus_msg) 0
#define MB_DeviceInentificationInit()
#endif
#ifndef MODBUS_ENABLE_DIAGNOSTICS
#define MB_DiagnosticsInit()
#define MB_Diagnostics_WriteBit(bit_num, bit_state) 0
#define MB_Diagnostics_GetBit(bit_num) 0
#define MB_Process_Diagnostics(modbus_msg) 0
#define MB_Diagnostics_BusMessageCnt()
#define MB_Diagnostics_CommunicationErrorCnt()
#define MB_Diagnostics_ExceptionErrorCnt()
#define MB_Diagnostics_CharacterOverrunCnt()
#define MB_Diagnostics_SlaveMessageCnt()
#define MB_Diagnostics_SlaveNoResponseCnt()
#define MB_Diagnostics_SlaveNAKCnt()
#define MB_Diagnostics_SlaveBusyCnt()
#define MB_GetDeviceMode() MODBUS_NORMAL_MODE
#endif
#ifndef MODBUS_ENABLE_MASTER
#define MB_RespGet_RegisterValue(modbus_msg, reg_addr, reg_value) 0
#define MB_RespGet_CoilState(modbus_msg, coil_addr, coil_state) 0
#define MB_RespGet_NumberOfObjects(modbus_msg) 0
#define MB_RespGet_ObjectById(modbus_msg, obj_id, obj_data, obj_length) 0
#define MB_RespGet_ObjectByIndex(modbus_msg, index, obj_id, obj_data, obj_length) 0
#define MB_RespGet_Diagnostic(modbus_msg, data) 0
#define MB_REQUEST_READ_COILS(slave_addr, start_addr, quantity) {0}
#define MB_REQUEST_READ_DISCRETE_INPUTS(slave_addr, start_addr, quantity) {0}
#define MB_REQUEST_READ_HOLDING_REGS(slave_addr, start_addr, quantity) {0}
#define MB_REQUEST_READ_INPUT_REGS(slave_addr, start_addr, quantity) {0}
#define MB_REQUEST_WRITE_SINGLE_COIL(slave_addr, coil_addr, value) {0}
#define MB_REQUEST_WRITE_SINGLE_REG(slave_addr, reg_addr, value) {0}
#define MB_REQUEST_WRITE_MULTIPLE_COILS(slave_addr, start_addr, quantity, coils_data) {0}
#define MB_REQUEST_WRITE_MULTIPLE_REGS(slave_addr, start_addr, quantity, regs_data) {0}
#define MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, sub_function, data) {0}
#define MB_REQUEST_RETURN_QUERY_DATA(slave_addr) {0}
#define MB_REQUEST_RESTART_COMMUNICATIONS(slave_addr, data) {0}
#define MB_REQUEST_RETURN_DIAGNOSTIC_REGISTER(slave_addr) {0}
#define MB_REQUEST_FORCE_LISTEN_ONLY_MODE(slave_addr) {0}
#define MB_REQUEST_CLEAR_COUNTERS_AND_DIAGNOSTIC_REGISTER(slave_addr) {0}
#define MB_REQUEST_RETURN_BUS_MESSAGE_COUNT(slave_addr) {0}
#define MB_REQUEST_RETURN_BUS_COMMUNICATION_ERROR_COUNT(slave_addr) {0}
#define MB_REQUEST_RETURN_SLAVE_EXCEPTION_ERROR_COUNT(slave_addr) {0}
#define MB_REQUEST_RETURN_SLAVE_MESSAGE_COUNT(slave_addr) {0}
#define MB_REQUEST_RETURN_SLAVE_NO_RESPONSE_COUNT(slave_addr) {0}
#define MB_REQUEST_RETURN_SLAVE_NAK_COUNT(slave_addr) {0}
#define MB_REQUEST_RETURN_SLAVE_BUSY_COUNT(slave_addr) {0}
#define MB_REQUEST_RETURN_BUS_CHARACTER_OVERRUN_COUNT(slave_addr) {0}
#define MB_REQUEST_READ_DEVICE_ID_BASIC(slave_addr) {0}
#define MB_REQUEST_READ_DEVICE_ID_REGULAR(slave_addr) {0}
#define MB_REQUEST_READ_DEVICE_ID_EXTENDED(slave_addr) {0}
#define MB_REQUEST_READ_DEVICE_ID_SPECIFIC(slave_addr, object_id) {0}
#define MB_Master_Collect_Message(hmodbus, modbus_msg, modbus_uart_buff) RS_ERR
#define MB_Master_Parse_Message(hmodbus, modbus_msg, modbus_uart_buff) RS_ERR
#endif
#ifndef MODBUS_ENABLE_SLAVE
#define MB_Slave_Response(hmodbus, modbus_msg) RS_ERR
#define MB_Slave_Collect_Message(hmodbus, modbus_msg, modbus_uart_buff) RS_ERR
#define MB_Slave_Parse_Message(hmodbus, modbus_msg, modbus_uart_buff) RS_ERR
#endif
/** @endcond */
#endif //__MODBUS_COMPAT_H_

View File

@@ -1,20 +1,22 @@
/** /**
****************************************************************************** *******************************************************************************
* @file modbus.h * @file modbus.h
* @brief Главный заголовочный файл Modbus библиотеки * @brief Главный заголовочный файл Modbus библиотеки
****************************************************************************** *******************************************************************************
@addtogroup MODBUS Modbus tools @addtogroup MODBUS Modbus tools
****************************************************************************** @brief Библиотека реализующая протокол Modbus
*******************************************************************************
@addtogroup MODBUS_FUNCTIONS Main API for Modbus Library @addtogroup MODBUS_FUNCTIONS Main API for Modbus Library
@ingroup MODBUS @ingroup MODBUS
@brief Публичные функции библиотеки
@{ @{
****************************************************************************** *******************************************************************************
* @details * @details
Объединяющий файл для подключения всей функциональности Modbus. Объединяющий файл для подключения всей функциональности Modbus.
Подключает все необходимые модули: Подключает все необходимые модули:
@section init Инструкция по подключению @section Start Инструкция по подключению
Для корректной работы надо: Для корректной работы надо:
- Подключить обработчики RS_UART_Handler(), RS_TIM_Handler(), в соответствубщие - Подключить обработчики RS_UART_Handler(), RS_TIM_Handler(), в соответствубщие
низкоуровневые прерывания UART_IRQHandler, TIM_IRQHandler вместо HAL'овского обработчика низкоуровневые прерывания UART_IRQHandler, TIM_IRQHandler вместо HAL'овского обработчика
@@ -23,32 +25,51 @@
- Инициализировать хендл мобдас. По умолчанию глобально создается hmodbus1 - Инициализировать хендл мобдас. По умолчанию глобально создается hmodbus1
- После для запуска Modbus: - После для запуска Modbus:
@verbatim @code
//----------------Слейв модбас----------------// //----------------Слейв модбас----------------//
#include "modbus.h" #include "modbus.h"
MODBUS_FirstInit(&hmodbus1, &huart1, &htim3); MODBUS_FirstInit(&hmodbus1, &huart1, &htim3, NULL); // NULL, если управление RE/DE не нужно
MODBUS_Config(&hmodbus1, 1, 1000, MODBUS_MODE_SLAVE); MODBUS_Config(&hmodbus1, MODBUS_DEVICE_ID, MODBUS_TIMEOUT, MODBUS_MODE_SLAVE);
MODBUS_SlaveStart(&hmodbus1, NULL); MODBUS_SlaveStart(&hmodbus1, NULL);
@endverbatim @endcode
@verbatim @code
//----------------Мастер модбас----------------// //----------------Мастер модбас----------------//
#include "modbus.h" #include "modbus.h"
MODBUS_FirstInit(&hmodbus1, &huart1, &htim3); MODBUS_FirstInit(&hmodbus1, &huart1, &htim3, NULL); // NULL, если управление RE/DE не нужно
MODBUS_Config(&hmodbus1, 0, 1000, MODBUS_MODE_MASTER); // - если нужны другие настройки, не из modbus_config.h MODBUS_Config(&hmodbus1, 0, MODBUS_TIMEOUT, MODBUS_MODE_MASTER);
// Запрос на 1 ID, считать холдинг регистры с 0 адреса 10 штук // Запрос на 1 ID, считать холдинг регистры с 0 адреса 10 штук
// При получении ответа вызовется функция callback_func()
RS_MsgTypeDef msg = MB_REQUEST_READ_HOLDING_REGS(1, 0, 10); RS_MsgTypeDef msg = MB_REQUEST_READ_HOLDING_REGS(1, 0, 10);
MODBUS_MasterRequest(&hmodbus1, &msg, &callback_func); MODBUS_MasterRequest(&hmodbus1, &msg, &callback_func);
void callback_func(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) void callback_func(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
{ {
// modbus_msg содержит ответ от устройства // MB_RespGet_... Чтобы достать нужные данные из ответа
if(hmodbus->RS_STATUS == RS_OK) // Получен ответ без ошибок
{
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;
} }
@endverbatim }
}
else // Ответ получен с ошибкой или не получен вовсе
{
}
}
@endcode
@section Подключаемые модули: @section modules Подключаемые модули:
- rs_message.h - работа с uart - rs_message.h - работа с uart
- modbus_core.h - базовые определения - modbus_core.h - базовые определения
- modbus_coils.h - работа с дискретными выходами - modbus_coils.h - работа с дискретными выходами
@@ -58,7 +79,7 @@
- modbus_diag.h - диагностика modbus - modbus_diag.h - диагностика modbus
@section Структура данных Modbus @section data Структура данных Modbus
#### Holding/Input Registers: #### Holding/Input Registers:
- Регистры — 16-битные слова. Доступ к регистрам осуществляется через указатель. - Регистры — 16-битные слова. Доступ к регистрам осуществляется через указатель.
@@ -73,15 +94,40 @@
#define __MODBUS_H_ #define __MODBUS_H_
#include "rs_message.h" #include "rs_message.h"
#ifdef MODBUS_ENABLE_MASTER
#include "modbus_master.h" #include "modbus_master.h"
#endif
#ifdef MODBUS_ENABLE_SLAVE
#include "modbus_slave.h" #include "modbus_slave.h"
#endif
#ifdef MODBUS_ENABLE_COILS
#include "modbus_coils.h" #include "modbus_coils.h"
#endif
#ifdef MODBUS_ENABLE_HOLDINGS
#include "modbus_holdregs.h" #include "modbus_holdregs.h"
#endif
#ifdef MODBUS_ENABLE_INPUTS
#include "modbus_inputregs.h" #include "modbus_inputregs.h"
#endif
#ifdef MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
#include "modbus_devid.h" #include "modbus_devid.h"
#endif
#ifdef MODBUS_ENABLE_DIAGNOSTICS
#include "modbus_diag.h" #include "modbus_diag.h"
#endif
#ifdef MODBUS_ENABLE_OSCIL
#include "modbus_oscil.h"
#endif
#include "modbus_data.h"
#ifdef MODBUS_ENABLE_MASTER
#define MODBUS_MODE_MASTER 1 ///< Псевдо-enum: Режим мастер
#endif
#ifdef MODBUS_ENABLE_SLAVE
#define MODBUS_MODE_SLAVE 0 ///< Псевдо-enum: Режим слейв
#endif
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
/////////////////////////---FUNCTIONS---///////////////////////////// /////////////////////////---FUNCTIONS---/////////////////////////////
@@ -90,7 +136,7 @@
//----------------FUNCTIONS FOR USER---------------- //----------------FUNCTIONS FOR USER----------------
/* Инициализация периферии модбас. */ /* Инициализация периферии модбас. */
HAL_StatusTypeDef MODBUS_FirstInit(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim); HAL_StatusTypeDef MODBUS_FirstInit(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, void (*pSetDirection)(int Tx));
/* Программная конфигурация модбас. */ /* Программная конфигурация модбас. */
HAL_StatusTypeDef 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);
/* Запуск слейв устройства */ /* Запуск слейв устройства */
@@ -99,7 +145,7 @@ HAL_StatusTypeDef MODBUS_SlaveStart(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mo
HAL_StatusTypeDef MODBUS_MasterRequest(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, void (*pClbk)(RS_HandleTypeDef*, RS_MsgTypeDef*)); HAL_StatusTypeDef MODBUS_MasterRequest(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, void (*pClbk)(RS_HandleTypeDef*, RS_MsgTypeDef*));
//---------PROCESS MODBUS COMMAND FUNCTIONS---------
/////////////////////////---FUNCTIONS---///////////////////////////// /////////////////////////---FUNCTIONS---/////////////////////////////
#endif //__MODBUS_H_ #endif //__MODBUS_H_
@@ -107,3 +153,4 @@ HAL_StatusTypeDef MODBUS_MasterRequest(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef
/** MODBUS_FUNCTIONS /** MODBUS_FUNCTIONS
* @} * @}
*/ */

View File

@@ -1,23 +1,27 @@
/** /**
****************************************************************************** *******************************************************************************
* @file modbus_coils.h * @file modbus_coils.h
* @brief Работа с коилами Modbus * @brief Работа с коилами Modbus
****************************************************************************** *******************************************************************************
@addtogroup MODBUS_COILS Coils Tools @addtogroup MODBUS_COILS Coils Tools
@ingroup MODBUS_INTERNAL @ingroup MODBUS_INTERNAL
****************************************************************************** @brief Функции для работы с коилами
*******************************************************************************
* @details * @details
Модуль для доступа к coils внутри программы:
- Функции для доступа к coils по глобальным адресам
- Макросы для доступа к coils по локальным адресам
Модуль предоставляет функции и макросы для работы с битовыми данными: Модуль предоставляет функции и макросы для работы с битовыми данными:
- Чтение coils (0x01) Упаковка битов в байты - Чтение coils (0x01) Упаковка битов в байты
- Запись одиночного coil (0x05) Установка/сброс бита - Запись одиночного coil (0x05) Установка/сброс бита
- Запись множественных coils (0x0F) - распаковка байтов в биты - Запись множественных coils (0x0F) - распаковка байтов в биты
- Макросы для локального доступа к coils
@section Организация битовых данных: @section cbits Организация битовых данных:
Coils упакованы в 16-битные слова для эффективного использования памяти. Coils упакованы в 16-битные слова для эффективного использования памяти.
Биты нумеруются от младшего к старшему внутри каждого слова. Биты нумеруются от младшего к старшему внутри каждого слова.
@section Адресация: @section caddr Адресация:
- Глобальная - абсолютный адрес в пространстве Modbus - Глобальная - абсолютный адрес в пространстве Modbus
- Локальная - относительный адрес внутри массива coils - Локальная - относительный адрес внутри массива coils
- Макросы автоматически вычисляют смещения и маски - Макросы автоматически вычисляют смещения и маски
@@ -26,6 +30,7 @@ Coils упакованы в 16-битные слова для эффективн
#ifndef __MODBUS_COILS_H_ #ifndef __MODBUS_COILS_H_
#define __MODBUS_COILS_H_ #define __MODBUS_COILS_H_
#include "modbus_core.h" #include "modbus_core.h"
#ifdef MODBUS_ENABLE_COILS
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
////////////////////---MODBUS FUNCTION DEFINES---//////////////////// ////////////////////---MODBUS FUNCTION DEFINES---////////////////////
@@ -34,100 +39,21 @@ Coils упакованы в 16-битные слова для эффективн
//-------------------------------------------------- //--------------------------------------------------
/**
* @addtogroup MODBUS_COILS
* @{
*/
/**
* @brief Макрос для установки указателя на регистр, содержащий запрашиваемый коил
* @param _parr_ - массив коилов.
* @param _coil_ - Номер коила от начала массива _arr_.
* @note Используется вместе с @ref MB_Set_Coil_Mask
@verbatim Пояснение выражений
- (_coil_/16) - индекс регистра, в котором содержится коил по адресу _coil_
Визуальный пример: 30 коил будет в 30/16 = 1 регистре (индексация с 0)
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx
|register[0]----| |register[1]----|
|skip this------| |get this-------|
|shift to 14 bit|
@endverbatim
*/
#define MB_Set_Coil_Reg_Ptr(_parr_, _coil_) ((uint16_t *)(_parr_)+((_coil_)/16))
/**
* @brief Макрос для установки маски, чтобы выделить запрашиваемый коил из регистра
* @param _coil_ - Номер коила от начала массива _arr_.
* @note Используется вместе с @ref MB_Set_Coil_Reg_Ptr
@verbatim Пояснение выражений
- (16*(_coil_/16) - сколько коилов нужно пропустить. прим. (16*30/16) - первые 16 коилов находятся вне регистра
- _coil_-(16*(_coil_/16)) - сдвинуть бит на место запрашиваемого коила в регистре
Визуальный пример: 30 коил будет регистре[1], на 14 бите:
register = 30/16 = 1
bit = 30 - (16*30/16) = 30 - 16 = 14
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx
|register[0]----| |register[1]----|
|skip this------| |get this-------|
|shift to 14 bit|
@endverbatim
*/
#define MB_Set_Coil_Mask(_coil_) (1 << ( _coil_ - (16*((_coil_)/16)) ))
/** MODBUS_COILS
* @}
*/
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
/////////////////////////---FUNCTIONS---///////////////////////////// /////////////////////////---FUNCTIONS---/////////////////////////////
/**
* @addtogroup MODBUS_REQ_COILS_API API for Coils
* @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 * @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS API for Data Access
* @ingroup MODBUS_FUNCTIONS * @ingroup MODBUS_FUNCTIONS
* @brief Функции для доступа к данным модбас * @brief API для доступа к данным модбас внутри программы
* @{ * @{
*/ */
/** @brief Structure for coils operation */ /** @brief Enum for coils operation */
typedef enum typedef enum
{ {
SET_COIL, SET_COIL,
@@ -178,10 +104,9 @@ uint16_t MB_Coil_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception);
* @} * @}
*/ */
//---------PROCESS MODBUS COMMAND FUNCTIONS---------
/** /**
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
@{ * @{
*/ */
/* Обработать функцию Read Coils (01 - 0x01) */ /* Обработать функцию Read Coils (01 - 0x01) */
uint8_t MB_Process_Read_Coils(RS_MsgTypeDef *modbus_msg); uint8_t MB_Process_Read_Coils(RS_MsgTypeDef *modbus_msg);
@@ -194,9 +119,5 @@ uint8_t MB_Process_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg);
* @} * @}
*/ */
/////////////////////////---FUNCTIONS---///////////////////////////// /////////////////////////---FUNCTIONS---/////////////////////////////
#endif //MODBUS_ENABLE_COILS
#endif //__MODBUS_COILS_H_ #endif //__MODBUS_COILS_H_
/** MODBUS_COILS
* @}
*/

View File

@@ -1,12 +1,13 @@
/** /**
****************************************************************************** *******************************************************************************
* @file modbus_core.h * @file modbus_core.h
* @brief Ядро Modbus протокола - определения и структуры * @brief Ядро Modbus протокола - определения и структуры
****************************************************************************** *******************************************************************************
@addtogroup MODBUS_INTERNAL Modbus Internal Tools @addtogroup MODBUS_INTERNAL Modbus Internal Tools
@ingroup MODBUS @ingroup MODBUS
@brief Внутренние штуки библиотеки
@{ @{
****************************************************************************** *******************************************************************************
* @details * @details
Базовые определения для реализации Modbus RTU устройства: Базовые определения для реализации Modbus RTU устройства:
- Структуры сообщений Modbus - Структуры сообщений Modbus
@@ -14,7 +15,7 @@
Константы размеров полей Константы размеров полей
Вспомогательные макросы Вспомогательные макросы
@section Структура сообщения: @section msg Структура сообщения:
[ADDR][FUNC][DATA...][CRC] [ADDR][FUNC][DATA...][CRC]
- Адрес: 1 байт - Адрес: 1 байт
- Функция: 1 байт - Функция: 1 байт
@@ -26,132 +27,147 @@
#define __MODBUS_CORE_H_ #define __MODBUS_CORE_H_
#include "modbus_config.h" #include "modbus_config.h"
#include "modbus_data.h"
#include "__crc_algs.h" #include "__crc_algs.h"
/** /**
* @addtogroup MODBUS_MESSAGE_DEFINES Modbus Message Tools * @addtogroup MODBUS_MESSAGE_DEFINES Modbus Message Tools
* @ingroup MODBUS * @ingroup MODBUS
* @brief Определения протокола модбас * @brief Определения протокола модбас
@{ * @{
*/ */
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
////////////////////---MODBUS MESSAGE DEFINES---///////////////////// ////////////////////---MODBUS MESSAGE DEFINES---/////////////////////
//-------------DEFINES FOR STRUCTURE---------------- //-------------DEFINES FOR STRUCTURE----------------
/* defines for structure of modbus message */ /* defines for structure of modbus message */
#define MbAddr_SIZE 1 ///< size of (MbAddr) #define MbTransactionID_size 2 ///< size of (Transaction ID)
#define Func_Code_SIZE 1 ///< size of (Func_Code) #define MbProtocolID_size 2 ///< size of (Protocol ID)
#define Addr_SIZE 2 ///< size of (Addr) #define MbPDULength_size 2 ///< size of (PDU Length)
#define Qnt_SIZE 2 ///< size of (Qnt) #define MbDeviceAddr_size 1 ///< size of (Slave Addr)
#define ByteCnt_SIZE 1 ///< size of (ByteCnt) #define MbFuncCode_size 1 ///< size of (Function Code)
#define DATA_SIZE 125 ///< maximum number of data: DWORD (NOT MESSAGE SIZE) #define MbAddr_size 2 ///< size of (Address)
#define CRC_SIZE 2 ///< size of (MB_CRC) in bytes #define MbQnt_size 2 ///< size of (Quantity)
#define MbByteCnt_size 1 ///< size of (Byte Count)
#define MbData_size 125 ///< maximum number of data: DWORD (NOT MESSAGE SIZE)
#define MbCRC_size 2 ///< size of (MbCRC) in bytes
/** @brief Size of whole message */ #ifndef MODBUS_PROTOCOL_TCP
#define INFO_SIZE_MAX (MbAddr_SIZE+Func_Code_SIZE+Addr_SIZE+Qnt_SIZE+ByteCnt_SIZE) /** @brief Size of whole RTU message */
#define RS_INFO_SIZE_MAX (MbDeviceAddr_size+MbFuncCode_size+MbAddr_size+MbQnt_size+MbByteCnt_size)
#else
/** @brief Size of whole TCP message */
#define RS_INFO_SIZE_MAX (MbTransactionID_size+MbProtocolID_size+MbPDULength_size+MbDeviceAddr_size+MbFuncCode_size+MbAddr_size+MbQnt_size)
#endif
/** @brief Size of first part of message that will be received /** @brief Size of first part of message that will be received
first receive info part of message, than defines size of rest message*/ first receive info part of message, than defines size of rest message*/
#define RX_FIRST_PART_SIZE INFO_SIZE_MAX #define RS_RX_FIRST_PART_SIZE RS_INFO_SIZE_MAX
/** @brief Size of buffer: max size of whole message */ /** @brief Size of buffer: max size of whole message */
#define MSG_SIZE_MAX (INFO_SIZE_MAX + DATA_SIZE*2 + CRC_SIZE) // max possible size of message #define RS_MSG_SIZE_MAX (RS_INFO_SIZE_MAX + MbData_size*2 + MbCRC_size) // max possible size of message
/** @brief Structure for modbus exception codes */ /**
* @brief Enum for modbus exception codes
* @details Prefix ET for Error Type
*/
typedef enum //MB_ExceptionTypeDef typedef enum //MB_ExceptionTypeDef
{ {
// reading /* Регулярные коды ошибок, которые определены конкретной программой */
NO_ERRORS = 0x00, ///< no errors ET_NO_ERRORS = 0x00, ///< no errors
ILLEGAL_FUNCTION = 0x01, ///< Принятый код функции не может быть обработан ET_ILLEGAL_FUNCTION = 0x01, ///< Принятый код функции не может быть обработан
ILLEGAL_DATA_ADDRESS = 0x02, ///< Адрес данных, указанный в запросе, недоступен ET_ILLEGAL_DATA_ADDRESS = 0x02, ///< Адрес данных, указанный в запросе, недоступен
ILLEGAL_DATA_VALUE = 0x03, ///< Значение, содержащееся в поле данных запроса, является недопустимой величиной ET_ILLEGAL_DATA_VALUE = 0x03, ///< Значение, содержащееся в поле данных запроса, является недопустимой величиной
SLAVE_DEVICE_FAILURE = 0x04, ///< Невосстанавливаемая ошибка имела место, пока ведомое устройство пыталось выполнить затребованное действие ET_SLAVE_DEVICE_FAILURE = 0x04, ///< Невосстанавливаемая ошибка имела место, пока ведомое устройство пыталось выполнить затребованное действие
// ACKNOWLEDGE = 0x05, ///< idk
// SLAVE_DEVICE_BUSY = 0x06, ///< idk /* Специальные коды ошибок, которые определены конкретной программой */
// MEMORY_PARITY_ERROR = 0x08, ///< idk ET_ACKNOWLEDGE = 0x05, ///< Устройство приняло запрос, но на обработку требуется время. Нужно чтобы не было Timeout ошибки
ET_SLAVE_DEVICE_BUSY = 0x06, ///< Устройство занято обработкой комманды
ET_MEMORY_PARITY_ERROR = 0x08, ///< Ошибка внешней памяти
}MB_ExceptionTypeDef; }MB_ExceptionTypeDef;
#define ERR_VALUES_START 0x80U ///< from this value starts error func codes #define FC_ERR_VALUES_START 0x80U ///< from this value starts error func codes
/** @brief Structure for modbus func codes */ /**
* @brief Enum for modbus func codes
* @details Prefix FC for Function Code
*/
typedef enum //MB_FunctonTypeDef typedef enum //MB_FunctonTypeDef
{ {
/* COMMANDS */ /* COMMANDS */
// reading // reading
MB_R_COILS = 0x01, ///< Чтение битовых ячеек FC_R_COILS = 0x01, ///< Чтение битовых ячеек
MB_R_DISC_IN = 0x02, ///< Чтение дискретных входов FC_R_DISC_IN = 0x02, ///< Чтение дискретных входов
#ifndef MODBUS_SWITCH_COMMAND_R_IN_REGS_AND_R_HOLD_REGS #ifndef MODBUS_SWITCH_COMMAND_R_IN_REGS_AND_R_HOLD_REGS
MB_R_HOLD_REGS = 0x03, ///< Чтение входных регистров FC_R_HOLD_REGS = 0x03, ///< Чтение входных регистров
MB_R_IN_REGS = 0x04, ///< Чтение регистров хранения FC_R_IN_REGS = 0x04, ///< Чтение регистров хранения
#else #else
MB_R_HOLD_REGS = 0x04, ///< Чтение входных регистров FC_R_HOLD_REGS = 0x04, ///< Чтение входных регистров
MB_R_IN_REGS = 0x03, ///< Чтение регистров хранения FC_R_IN_REGS = 0x03, ///< Чтение регистров хранения
#endif #endif
// writting // writting
MB_W_COIL = 0x05, ///< Запись битовой ячейки FC_W_COIL = 0x05, ///< Запись битовой ячейки
MB_W_HOLD_REG = 0x06, ///< Запись одиночного регистра FC_W_HOLD_REG = 0x06, ///< Запись одиночного регистра
MB_W_COILS = 0x0F, ///< Запись нескольких битовых ячеек FC_W_COILS = 0x0F, ///< Запись нескольких битовых ячеек
MB_W_HOLD_REGS = 0x10, ///< Запись нескольких регистров FC_W_HOLD_REGS = 0x10, ///< Запись нескольких регистров
MB_R_DIAGNOSTIC = 0x08, ///< Чтение диагностической информации устройства FC_R_DIAGNOSTICS = 0x08, ///< Чтение диагностической информации устройства
MB_R_DEVICE_INFO = 0x2B, ///< Чтение информации об устройстве FC_R_DEVICE_ID = 0x2B, ///< Чтение информации об устройстве
/* ERRORS */ /* ERRORS */
// error reading // error reading
MB_ERR_R_COILS = MB_R_COILS + ERR_VALUES_START, ///< Ошибка чтения битовых ячеек FC_ERR_R_COILS = FC_R_COILS + FC_ERR_VALUES_START, ///< Ошибка чтения битовых ячеек
MB_ERR_R_DISC_IN = MB_R_DISC_IN + ERR_VALUES_START, ///< Ошибка чтения дискретных входов FC_ERR_R_DISC_IN = FC_R_DISC_IN + FC_ERR_VALUES_START, ///< Ошибка чтения дискретных входов
MB_ERR_R_IN_REGS = MB_R_IN_REGS + ERR_VALUES_START, ///< Ошибка чтения регистров хранения FC_ERR_R_IN_REGS = FC_R_IN_REGS + FC_ERR_VALUES_START, ///< Ошибка чтения регистров хранения
MB_ERR_R_HOLD_REGS = MB_R_HOLD_REGS + ERR_VALUES_START, ///< Ошибка чтения входных регистров FC_ERR_R_HOLD_REGS = FC_R_HOLD_REGS + FC_ERR_VALUES_START, ///< Ошибка чтения входных регистров
// error writting // error writting
MB_ERR_W_COIL = MB_W_COIL + ERR_VALUES_START, ///< Ошибка записи битовой ячейки FC_ERR_W_COIL = FC_W_COIL + FC_ERR_VALUES_START, ///< Ошибка записи битовой ячейки
MB_ERR_W_HOLD_REG = MB_W_HOLD_REG + ERR_VALUES_START, ///< Ошибка записи одиночного регистра FC_ERR_W_HOLD_REG = FC_W_HOLD_REG + FC_ERR_VALUES_START, ///< Ошибка записи одиночного регистра
MB_ERR_W_COILS = MB_W_COILS + ERR_VALUES_START, ///< Ошибка записи нескольких битовых ячеек FC_ERR_W_COILS = FC_W_COILS + FC_ERR_VALUES_START, ///< Ошибка записи нескольких битовых ячеек
MB_ERR_W_HOLD_REGS = MB_W_HOLD_REGS + ERR_VALUES_START, ///< Ошибка записи нескольких регистров FC_ERR_W_HOLD_REGS = FC_W_HOLD_REGS + FC_ERR_VALUES_START, ///< Ошибка записи нескольких регистров
MB_ERR_R_DIAGNOSTIC = MB_R_DIAGNOSTIC + ERR_VALUES_START, ///< Ошибка чтения диагностической информации устройства FC_ERR_R_DIAGNOSTIC = FC_R_DIAGNOSTICS + FC_ERR_VALUES_START, ///< Ошибка чтения диагностической информации устройства
MB_ERR_R_DEVICE_INFO = MB_R_DEVICE_INFO + ERR_VALUES_START, ///< Ошибка чтения информации об устройстве FC_ERR_R_DEVICE_INFO = FC_R_DEVICE_ID + FC_ERR_VALUES_START, ///< Ошибка чтения информации об устройстве
}MB_FunctonTypeDef; }MB_FunctonTypeDef;
/** @brief Structure for MEI func codes */ /**
* @brief Enum for MEI func codes
*/
typedef enum //MB_FunctonTypeDef typedef enum //MB_FunctonTypeDef
{ {
MEI_DEVICE_IDENTIFICATIONS = 0x0E, MEI_DEVICE_IDENTIFICATIONS = 0x0E,
}MB_MEITypeDef; }MB_MEITypeDef;
/** @brief Structure for comformity */ /**
* @brief Enum for Read Device Id codes
* @details Prefix RID for Read ID
*/
typedef enum //MB_FunctonTypeDef typedef enum //MB_FunctonTypeDef
{ {
MB_BASIC_IDENTIFICATIONS = 0x01, /*!< @brief Basic Device Identifications. RID_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_IDENTIFICATIONS = 0x02, /*!< @brief Regular Device Identifications. RID_REGULAR_IDENTIFICATIONS = 0x02, /*!< @brief Regular Device Identifications.
@details The device provides additional and optional @details The device provides additional and optional
identifications and description data objects */ identifications and description data objects */
MB_EXTENDED_IDENTIFICATIONS = 0x03, /*!< @brief Extended Device Identifications. RID_EXTENDED_IDENTIFICATIONS = 0x03, /*!< @brief Extended Device Identifications.
@details The device provides additional and optional @details The device provides additional and optional
identifications 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_IDENTIFICATIONS = 0x04, /*!< @brief Specific Device Identifications. RID_SPEDIFIC_IDENTIFICATIONS = 0x04, /*!< @brief Specific Device Identifications.
@details The device provides one specific identifications object. */ @details The device provides one specific identifications object. */
/* ERRORS */ }MB_ReadDevId;
MB_ERR_BASIC_IDENTIFICATIONS = MB_BASIC_IDENTIFICATIONS + ERR_VALUES_START,
MB_ERR_REGULAR_IDENTIFICATIONS = MB_REGULAR_IDENTIFICATIONS + ERR_VALUES_START,
MB_ERR_EXTENDED_IDENTIFICATIONS = MB_REGULAR_IDENTIFICATIONS + ERR_VALUES_START,
MB_ERR_SPEDIFIC_IDENTIFICATIONS = MB_REGULAR_IDENTIFICATIONS + ERR_VALUES_START,
}MB_ConformityTypeDef;
/** @brief Structure for decive identifications message type */ /** @brief Structure for device identifications message type */
typedef struct typedef struct
{ {
MB_MEITypeDef MEI_Type; ///< MEI Type assigned number for Device Identifications Interface MB_MEITypeDef MEI_Type; ///< MEI Type assigned number for Device Identifications Interface
MB_ConformityTypeDef ReadDevId; MB_ReadDevId ReadDevId;
MB_ConformityTypeDef Conformity; uint8_t Conformity; ///< Identification conformity level of the device and type of supported access @ref MODBUS_DEVICE_CONFORMITY
uint8_t MoreFollows; uint8_t MoreFollows;
uint8_t NextObjId; uint8_t NextObjId;
uint8_t NumbOfObj; uint8_t NumbOfObj;
@@ -161,17 +177,23 @@ typedef struct
/** @brief Structure for modbus messsage */ /** @brief Structure for modbus messsage */
typedef struct // RS_MsgTypeDef typedef struct // RS_MsgTypeDef
{ {
uint8_t MbAddr; ///< Modbus Slave Address #ifdef MODBUS_PROTOCOL_TCP
MB_FunctonTypeDef Func_Code; ///< Modbus Function Code uint16_t TransactionID; ///< Modbus TCP: ID Transaction
uint16_t ProtocolID; ///< Modbus TCP: ID Protocol
uint16_t PDULength; ///< Modbus TCP: PDU Length
#endif
uint8_t DeviceAddr; ///< Modbus Slave Address
MB_FunctonTypeDef FuncCode; ///< Modbus Function Code
MB_DevIdMsgTypeDef DevId; ///< Read Device Identifications 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
uint16_t DATA[DATA_SIZE]; ///< Modbus Data uint16_t MbData[MbData_size]; ///< Modbus Data
MB_ExceptionTypeDef Except_Code; ///< Exception Code for the command MB_ExceptionTypeDef Except_Code; ///< Exception Code for the command
uint16_t MB_CRC; ///< Modbus CRC uint16_t MbCRC; ///< Modbus CRC
}RS_MsgTypeDef; }RS_MsgTypeDef;
//-------------------------------------------------- //--------------------------------------------------
extern RS_MsgTypeDef MODBUS_MSG; extern RS_MsgTypeDef MODBUS_MSG;
@@ -194,6 +216,42 @@ extern RS_MsgTypeDef MODBUS_MSG;
*/ */
#define MB_Set_Register_Ptr(_parr_, _addr_) ((uint16_t *)(_parr_)+(_addr_)) #define MB_Set_Register_Ptr(_parr_, _addr_) ((uint16_t *)(_parr_)+(_addr_))
/**
* @brief Макрос для установки указателя на регистр, содержащий запрашиваемый коил
* @param _parr_ - массив коилов.
* @param _coil_ - Номер коила от начала массива _arr_.
* @note Используется вместе с @ref MB_Set_Coil_Mask
@code Пояснение выражений
- (_coil_/16) - индекс регистра, в котором содержится коил по адресу _coil_
Визуальный пример: 30 коил будет в 30/16 = 1 регистре (индексация с 0)
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx
|register[0]----| |register[1]----|
|skip this------| |get this-------|
|shift to 14 bit|
@endcode
*/
#define MB_Set_Coil_Reg_Ptr(_parr_, _coil_) ((uint16_t *)(_parr_)+((_coil_)/16))
/**
* @brief Макрос для установки маски, чтобы выделить запрашиваемый коил из регистра
* @param _coil_ - Номер коила от начала массива _arr_.
* @note Используется вместе с @ref MB_Set_Coil_Reg_Ptr
@code Пояснение выражений
- (16*(_coil_/16) - сколько коилов нужно пропустить. прим. (16*30/16) - первые 16 коилов находятся вне регистра
- _coil_-(16*(_coil_/16)) - сдвинуть бит на место запрашиваемого коила в регистре
Визуальный пример: 30 коил будет регистре[1], на 14 бите:
register = 30/16 = 1
bit = 30 - (16*30/16) = 30 - 16 = 14
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx
|register[0]----| |register[1]----|
|skip this------| |get this-------|
|shift to 14 bit|
@endcode
*/
#define MB_Set_Coil_Mask(_coil_) (1 << ( _coil_ - (16*((_coil_)/16)) ))
/** GENERAL_MODBUS_STUFF /** GENERAL_MODBUS_STUFF
* @} * @}
*/ */
@@ -233,10 +291,9 @@ extern RS_MsgTypeDef MODBUS_MSG;
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
/////////////////////////---FUNCTIONS---///////////////////////////// /////////////////////////---FUNCTIONS---/////////////////////////////
//---------PROCESS MODBUS COMMAND FUNCTIONS---------
/** /**
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
@{ * @{
*/ */
/* Реализация этих функций лежит в modbus_data.c */ /* Реализация этих функций лежит в modbus_data.c */
@@ -244,14 +301,17 @@ extern RS_MsgTypeDef MODBUS_MSG;
/* Check is address valid for certain array */ /* Check is address valid for certain array */
MB_ExceptionTypeDef MB_Check_Address_For_Arr(uint16_t Addr, uint16_t Qnt, uint16_t R_ARR_ADDR, uint16_t R_ARR_NUMB); MB_ExceptionTypeDef MB_Check_Address_For_Arr(uint16_t Addr, uint16_t Qnt, uint16_t R_ARR_ADDR, uint16_t R_ARR_NUMB);
/* Define Address Origin for Input/Holding Registers */ /* Define Address Origin for Input/Holding Registers */
MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, uint16_t Qnt, uint8_t RegisterType); MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, uint16_t Qnt, uint8_t RegisterType, uint8_t WriteFlag);
/* Define Address Origin for coils */ /* Define Address Origin for coils */
MB_ExceptionTypeDef MB_DefineCoilsAddress(uint16_t **pCoils, uint16_t Addr, uint16_t Qnt, uint16_t *start_shift, uint8_t WriteFlag); MB_ExceptionTypeDef MB_DefineCoilsAddress(uint16_t **pCoils, uint16_t Addr, uint16_t Qnt, uint16_t *start_shift, uint8_t WriteFlag);
/** MODBUS_CMD_PROCESS_FUNCTIONS /** MODBUS_CMD_PROCESS_FUNCTIONS
* @} * @}
*/ */
/////////////////////////---FUNCTIONS---///////////////////////////// /////////////////////////---FUNCTIONS---/////////////////////////////
#include "__modbus_compat.h"
#endif //__MODBUS_CORE_H_ #endif //__MODBUS_CORE_H_
/** MODBUS_INTERNAL /** MODBUS_INTERNAL
* @} * @}
*/ */

View File

@@ -1,18 +1,19 @@
/** /**
****************************************************************************** *******************************************************************************
* @file modbus_devid.h * @file modbus_devid.h
* @brief Идентификаторы устройства Modbus * @brief Идентификаторы устройства Modbus
****************************************************************************** *******************************************************************************
@addtogroup MODBUS_DEVID Device Identifications Tools @addtogroup MODBUS_DEVID Device Identifications Tools
@ingroup MODBUS_INTERNAL @ingroup MODBUS_INTERNAL
****************************************************************************** @brief Функции для работы с идентификаторами устройства
*******************************************************************************
* @details * @details
Модуль реализации функции Read Device Identifications (0x2B): Модуль реализации функции Read Device Identifications (0x2B):
- Базовая идентификация (Vendor, Product, Revision) - Базовая идентификация (Vendor, Product, Revision)
- Расширенная идентификация (URL, Model, User fields) - Расширенная идентификация (URL, Model, User fields)
- Поддержка потоковой передачи больших объектов - Поддержка потоковой передачи больших объектов
@section Объекты идентификации: @section devobj Объекты идентификации:
- VendorName, ProductCode, Revision - обязательные - VendorName, ProductCode, Revision - обязательные
- VendorUrl, ProductName, ModelName - опциональные - VendorUrl, ProductName, ModelName - опциональные
- User objects - пользовательские поля - User objects - пользовательские поля
@@ -21,6 +22,7 @@
#ifndef __MODBUS_DEVID_H_ #ifndef __MODBUS_DEVID_H_
#define __MODBUS_DEVID_H_ #define __MODBUS_DEVID_H_
#include "modbus_core.h" #include "modbus_core.h"
#ifdef MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
@@ -31,6 +33,12 @@
* @{ * @{
*/ */
#if MODBUS_NUMB_OF_USEROBJECTS > 0
#define MODBUS_DEVICE_CONFORMITY 0x83
#else
#define MODBUS_DEVICE_CONFORMITY 0x82
#endif
/** @brief Структура для объекта (идентификатора устройства модбас) */ /** @brief Структура для объекта (идентификатора устройства модбас) */
typedef struct typedef struct
{ {
@@ -86,52 +94,6 @@ void MB_DeviceInentificationInit(void);
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
/////////////////////////---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 * @addtogroup MODBUS_DEVID
* @{ * @{
@@ -145,10 +107,10 @@ void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj);
/** MODBUS_DEVID /** MODBUS_DEVID
* @} * @}
*/ */
//---------PROCESS MODBUS COMMAND FUNCTIONS---------
/** /**
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
@{ * @{
*/ */
/* Обработать функцию Read Device Identifications (43/14 - 0x2B/0E) */ /* Обработать функцию Read Device Identifications (43/14 - 0x2B/0E) */
@@ -158,4 +120,6 @@ uint8_t MB_Process_Read_Device_Identifications(RS_MsgTypeDef *modbus_msg);
*/ */
/////////////////////////---FUNCTIONS---///////////////////////////// /////////////////////////---FUNCTIONS---/////////////////////////////
#endif //MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
#endif //__MODBUS_DEVID_H_ #endif //__MODBUS_DEVID_H_

View File

@@ -1,11 +1,12 @@
/** /**
****************************************************************************** *******************************************************************************
* @file modbus_diag.h * @file modbus_diag.h
* @brief Диагностика устройства Modbus * @brief Диагностика устройства Modbus
****************************************************************************** *******************************************************************************
@addtogroup MODBUS_DIAG Diagnostics Tools @addtogroup MODBUS_DIAG Diagnostics Tools
@ingroup MODBUS_INTERNAL @ingroup MODBUS_INTERNAL
****************************************************************************** @brief Функции для работы с диагностикой
*******************************************************************************
* @details * @details
Модуль реализации Diagnostics (Serial Line only) (0x08): Модуль реализации Diagnostics (Serial Line only) (0x08):
- Полная поддержка всех подфункций диагностики - Полная поддержка всех подфункций диагностики
@@ -16,6 +17,7 @@
#ifndef __MODBUS_DIAG_H_ #ifndef __MODBUS_DIAG_H_
#define __MODBUS_DIAG_H_ #define __MODBUS_DIAG_H_
#include "modbus_core.h" #include "modbus_core.h"
#ifdef MODBUS_ENABLE_DIAGNOSTICS
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
/////////////////---DEVICE DIAGNOSTICS DEFINES---//////////////////// /////////////////---DEVICE DIAGNOSTICS DEFINES---////////////////////
@@ -65,29 +67,6 @@ void MB_DiagnosticsInit(void);
* @} * @}
*/ */
/**
* @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
* @}
*/
@@ -121,10 +100,9 @@ void MB_Diagnostics_SlaveBusyCnt(void);
* @} * @}
*/ */
//---------PROCESS MODBUS COMMAND FUNCTIONS---------
/** /**
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
@{ * @{
*/ */
/* Обработка команды диагностики (0x08) */ /* Обработка команды диагностики (0x08) */
@@ -139,8 +117,10 @@ uint8_t MB_Process_Diagnostics(RS_MsgTypeDef *modbus_msg);
/////////////////////////---FUNCTIONS---///////////////////////////// /////////////////////////---FUNCTIONS---/////////////////////////////
#endif //MODBUS_ENABLE_DIAGNOSTICS
#endif //__MODBUS_DIAG_H_ #endif //__MODBUS_DIAG_H_
/** MODBUS_DIAG /** MODBUS_DIAG
* @} * @}
*/ */

View File

@@ -1,32 +1,52 @@
/** /**
****************************************************************************** *******************************************************************************
* @file modbus_holdregs.h * @file modbus_holdregs.h
* @brief Работа с регистрами хранения Modbus * @brief Работа с регистрами хранения Modbus
****************************************************************************** *******************************************************************************
@addtogroup MODBUS_INS Input Register Tools @addtogroup MODBUS_HOLD Holding Registers Tools
@ingroup MODBUS_INTERNAL @ingroup MODBUS_INTERNAL
****************************************************************************** @brief Функции для работы с регистрами хранения
*******************************************************************************
* @details * @details
Модуль для доступа к регистрам внутри программы:
- Функции для доступа к регистрам хранения по глобальным адресам
Модуль обработки команд для регистров хранения (Holding Registers): Модуль обработки команд для регистров хранения (Holding Registers):
- Чтение множества регистров (0x03) - Чтение множества регистров (0x03)
- Запись одиночного регистра (0x06) - Запись одиночного регистра (0x06)
- Запись множества регистров (0x10) - Запись множества регистров (0x10)
@section Регистры хранения: @section hold Регистры хранения:
- Read/Write доступ - Read/Write доступ
- 16-битные значения (uint16_t) - 16-битные значения (uint16_t)
******************************************************************************/ ******************************************************************************/
#ifndef __MODBUS_HOLDREGS_H_ #ifndef __MODBUS_HOLDREGS_H_
#define __MODBUS_HOLDREGS_H_ #define __MODBUS_HOLDREGS_H_
#include "modbus_core.h" #include "modbus_core.h"
#ifdef MODBUS_ENABLE_HOLDINGS
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
/////////////////////////---FUNCTIONS---///////////////////////////// /////////////////////////---FUNCTIONS---/////////////////////////////
//---------PROCESS MODBUS COMMAND FUNCTIONS--------- /**
* @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS
* @{
*/
/* Записать регистр хранения по глобальному адресу. */
MB_ExceptionTypeDef MB_Holding_Write_Global(uint16_t Addr, uint16_t WriteVal);
/* Считать регистр хранения по глобальному адресу. */
uint16_t MB_Holding_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception);
/** MODBUS_DATA_ACCESS_FUNCTIONS
* @}
*/
/** /**
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
@{ * @{
*/ */
/* Обработать функцию Read Holding Registers (03 - 0x03) */ /* Обработать функцию Read Holding Registers (03 - 0x03) */
uint8_t MB_Process_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg); uint8_t MB_Process_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg);
@@ -40,4 +60,5 @@ uint8_t MB_Process_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg);
*/ */
/////////////////////////---FUNCTIONS---///////////////////////////// /////////////////////////---FUNCTIONS---/////////////////////////////
#endif //MODBUS_ENABLE_HOLDINGS
#endif //__MODBUS_HOLDREGS_H_ #endif //__MODBUS_HOLDREGS_H_

View File

@@ -1,32 +1,51 @@
/** /**
****************************************************************************** *******************************************************************************
* @file modbus_inputregs.h * @file modbus_inputregs.h
* @brief Работа с входными регистрами Modbus * @brief Работа с входными регистрами Modbus
****************************************************************************** *******************************************************************************
@addtogroup MODBUS_HOLD Holding Registers Tools @addtogroup MODBUS_INS Input Register Tools
@ingroup MODBUS_INTERNAL @ingroup MODBUS_INTERNAL
****************************************************************************** @brief Функции для работы с входными регистрами
*******************************************************************************
* @details * @details
Модуль для доступа к регистрам внутри программы:
- Функции для доступа к входным регистрам по глобальным адресам
Модуль обработки команд для входных регистров (Input Registers): Модуль обработки команд для входных регистров (Input Registers):
- Чтение множества регистров (0x04) - Чтение множества регистров (0x04)
@section Входные регистры: @section in Входные регистры:
- Read-Only доступ - Read-Only доступ
- 16-битные значения - 16-битные значения
******************************************************************************/ ******************************************************************************/
#ifndef __MODBUS_INPUTREGS_H_ #ifndef __MODBUS_INPUTREGS_H_
#define __MODBUS_INPUTREGS_H_ #define __MODBUS_INPUTREGS_H_
#include "modbus_core.h" #include "modbus_core.h"
#ifdef MODBUS_ENABLE_INPUTS
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
/////////////////////////---FUNCTIONS---///////////////////////////// /////////////////////////---FUNCTIONS---/////////////////////////////
//---------PROCESS MODBUS COMMAND FUNCTIONS--------- /**
* @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS
* @{
*/
/* Записать входной регистр по глобальному адресу. */
MB_ExceptionTypeDef MB_Input_Write_Global(uint16_t Addr, uint16_t WriteVal);
/* Считать входной регистр по глобальному адресу. */
uint16_t MB_Input_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception);
/** MODBUS_DATA_ACCESS_FUNCTIONS
* @}
*/
/** /**
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS Internal Process Functions * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS Internal Process Functions
* @ingroup MODBUS_INTERNAL * @ingroup MODBUS_INTERNAL
* @brief Функции обработки запросов модбас * @brief Функции обработки запросов модбас
@{ * @{
*/ */
/* Обработать функцию Read Input Registers (04 - 0x04) */ /* Обработать функцию Read Input Registers (04 - 0x04) */
uint8_t MB_Process_Read_Input_Regs(RS_MsgTypeDef *modbus_msg); uint8_t MB_Process_Read_Input_Regs(RS_MsgTypeDef *modbus_msg);
@@ -36,4 +55,5 @@ uint8_t MB_Process_Read_Input_Regs(RS_MsgTypeDef *modbus_msg);
*/ */
/////////////////////////---FUNCTIONS---///////////////////////////// /////////////////////////---FUNCTIONS---/////////////////////////////
#endif //MODBUS_ENABLE_INPUTS
#endif //__MODBUS_INPUTREGS_H_ #endif //__MODBUS_INPUTREGS_H_

View File

@@ -1,27 +1,24 @@
/** /**
****************************************************************************** *******************************************************************************
* @file modbus_master.h * @file modbus_master.h
* @brief Главный заголовочный файл Modbus библиотеки * @brief Главный заголовочный файл Modbus библиотеки
****************************************************************************** *******************************************************************************
@addtogroup MODBUS_MASTER Modbus master funtions @addtogroup MODBUS_MASTER Modbus master funtions
@ingroup MODBUS_CMD_PROCESS_FUNCTIONS @ingroup MODBUS_CMD_PROCESS_FUNCTIONS
****************************************************************************** @brief Функции для работы в режиме Master
*******************************************************************************
* @details * @details
Модуль реализации обработки UART сообщение в режиме мастер Модуль реализации Modbus в режиме мастер
******************************************************************************/ ******************************************************************************/
#ifndef __MODBUS_MASTER_H_ #ifndef __MODBUS_MASTER_H_
#define __MODBUS_MASTER_H_ #define __MODBUS_MASTER_H_
#include "rs_message.h" #include "rs_message.h"
#ifdef MODBUS_ENABLE_MASTER #ifdef MODBUS_ENABLE_MASTER
#define MODBUS_MODE_MASTER 1
#endif
/** /**
* @addtogroup MODBUS_REQUEST_MSG API for Master Requests * @addtogroup MODBUS_REQUEST_MSG API for Master Requests
* @ingroup MODBUS_FUNCTIONS * @ingroup MODBUS_FUNCTIONS
* @brief Макросы для создания запросов в режиме мастер * @brief API для формирования фрейма-запроса в режиме мастер
* @details Примеры использования: * @details Примеры использования:
* @code * @code
* // Чтение 10 holding registers начиная с адреса 0 * // Чтение 10 holding registers начиная с адреса 0
@@ -84,24 +81,20 @@ RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_SPECIFIC(uint8_t slave_addr, uint8_t obj
* @code * @code
* // Пример: Запросили 10 регистров с адреса 100, хотим получить значение регистра 105 * // Пример: Запросили 10 регистров с адреса 100, хотим получить значение регистра 105
* uint16_t reg_value; * uint16_t reg_value;
* if(MB_RespGet_RegisterValue(&MODBUS_MSG, 105, &reg_value)) * if(MB_RespGet_RegisterValue(modbus_msg, 105, &reg_value))
* { * {
* printf("Register 105 value: %d\n", reg_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 reg_value[125];
* { * MB_RespGet_RegisterAll(modbus_msg)
* uint16_t value;
* if(MB_RespGet_RegisterValue(&MODBUS_MSG, addr, &value))
* {
* printf("Register %d: %d\n", addr, value);
* }
* }
* @endcode * @endcode
* @{ * @{
*/ */
/* Получить значение ВСЕХ регистров в ответе */
int MB_RespGet_RegisterAll(RS_MsgTypeDef *modbus_msg, uint16_t *reg_arr);
/* Получить значение регистра в ответе по его адресу */
int MB_RespGet_RegisterValue(RS_MsgTypeDef *modbus_msg, uint16_t reg_addr, uint16_t *reg_value); int MB_RespGet_RegisterValue(RS_MsgTypeDef *modbus_msg, uint16_t reg_addr, uint16_t *reg_value);
@@ -109,6 +102,118 @@ int MB_RespGet_RegisterValue(RS_MsgTypeDef *modbus_msg, uint16_t reg_addr, uint1
* @} * @}
*/ */
/**
* @addtogroup MODBUS_REQ_COILS_API API for Coils
* @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
* @{
*/
/* Получить состояние ВСЕХ coil в ответе */
int MB_RespGet_CoilAll(RS_MsgTypeDef *modbus_msg, int *coil_arr);
/* Получить состояние coil в ответе по его адресу */
int MB_RespGet_CoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coil_state);
/** MODBUS_REQ_COILS_API
* @}
*/
/**
* @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_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_MASTER * @addtogroup MODBUS_MASTER
* @{ * @{
@@ -123,4 +228,5 @@ RS_StatusTypeDef MB_Master_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDe
* @} * @}
*/ */
#endif //MODBUS_ENABLE_MASTER
#endif //__MODBUS_MASTER_H_ #endif //__MODBUS_MASTER_H_

111
Inc/modbus_oscil.h Normal file
View File

@@ -0,0 +1,111 @@
/**
*******************************************************************************
* @file modbus_oscil.h
* @brief Заголовочный файл модуля осциллографа через MODBUS.
*******************************************************************************
* @addtogroup MODBUS_OSCIL Modbus Oscilloscope
* @ingroup MODBUS
* @brief Модуль для сбора и хранения данных осциллографа
* @details
* Реализует кольцевой буфер для хранения данных с нескольких каналов
* с возможностью чтения через Modbus. Данные 8-битные, упаковываются
* по 2 сэмпла в 16-битный регистр Modbus.
*
* Карта Modbus регистров (адрес относительный):
* | Адрес | Биты | Назначение | Диапазон | Описание |
* |--------|------|------------|----------|----------|
* | 0x0000 | 0-3 | channels | 1-16 | Количество каналов |
* | | 4-7 | reserved | 0 | Зарезервировано |
* | | 8-15 | buffer_size| 1-125 | Размер буфера в регистрах |
* | 0x0001 | 0-7 | tail | 0-124 | Начало новых данных |
* | | 8-15 | head | 0-124 | Конец новых данных |
* | 0x0002...| 0-15| data | - | Буфер данных |
* @{
******************************************************************************/
#ifndef __MODBUS_OSCIL_H_
#define __MODBUS_OSCIL_H_
#include "modbus_core.h"
#ifdef MODBUS_ENABLE_OSCIL
/**
* @brief Структура конфигурации осциллографа
*/
typedef struct
{
/* Адрес 0 */
uint16_t Overrun:1; ///< Overrun
uint16_t NumbOfChannels:4; ///< Количество каналов (1-16)
uint16_t BufferSize:7; ///< Размер буфера в регистрах (1-125)
uint16_t SampleTime; ///< Адрес 1: Время между сэмплами в мкс/мс
uint16_t reserved[2]; ///< Резерв
uint32_t LastTick; ///< Адрес 4-5: Время последнего добавления (uint32_t)
} MB_ConfigTypeDef;
/**
* @brief Структура указателей буфера
*/
typedef struct
{
uint16_t Head:8; ///< Указатель на последний записанный байт
uint16_t Tail:8; ///< Указатель на начало непрочитанных данных (байты)
} MB_PreambleTypeDef;
/**
* @brief Основная структура осциллографа
*/
typedef struct
{
MB_ConfigTypeDef Config; /*!< @brief Отн. Адрес 0-6: Конфигурация */
uint16_t User[4]; /*!< @brief Отн. Адрес 6-9: Пользовательские регистры */
MB_PreambleTypeDef Preamble; /*!< @brief Отн. Адрес 10: Указатели head и tail буфера */
uint8_t Data[MbData_size*2-1]; ///< /*!< @brief Отн. Адрес 11-131: Буфер данных (в байтах) */
} MB_OscilTypeDef;
/**
* @addtogroup MODBUS_OSCIL_API API for Oscilloscope
* @ingroup MODBUS_OSCIL
* @brief API для работы с буфером осциллографа
* @details Примеры использования:
* @code
* MB_OscilTypeDef oscil;
*
* // Инициализация осциллографа
* MB_Oscil_Init(&oscil, 120, 4, 1000);
*
* // В цикле сбора данных
* uint8_t ch_data[4] = {adc1, adc2, adc3, adc4};
* MB_Oscil_Add(&oscil, ch_data);
*
* // После чтения данных через Modbus
* MB_Oscil_UpdateTail(&oscil);
* @endcode
* @{
*/
/* Инициализация структуры осциллографа */
HAL_StatusTypeDef MB_Oscil_Init(MB_OscilTypeDef *oscil, uint8_t BufferSize, uint8_t NumbOfChannels, uint16_t SampleTime);
/* Добавление данных всех каналов в буфер */
HAL_StatusTypeDef MB_Oscil_Add(MB_OscilTypeDef *oscil, uint8_t *Data);
/* Обновление указателя Tail */
HAL_StatusTypeDef MB_Oscil_UpdateTail(MB_OscilTypeDef *oscil);
/** MODBUS_OSCIL_API
* @}
*/
#endif //MODBUS_ENABLE_OSCIL
#endif //__MODBUS_OSCIL_H_
/** MODBUS_OSCIL
* @}
*/

View File

@@ -1,28 +1,30 @@
/** /**
****************************************************************************** *******************************************************************************
* @file modbus_slave.h * @file modbus_slave.h
* @brief Главный заголовочный файл Modbus библиотеки * @brief Главный заголовочный файл Modbus библиотеки
****************************************************************************** *******************************************************************************
@addtogroup MODBUS_SLAVE Modbus slave funtions @addtogroup MODBUS_SLAVE Modbus slave funtions
@ingroup MODBUS_CMD_PROCESS_FUNCTIONS @ingroup MODBUS_CMD_PROCESS_FUNCTIONS
****************************************************************************** @brief Функции для работы в режиме Slave
*******************************************************************************
* @details * @details
Модуль реализации обработки UART сообщение в режиме слейв Модуль реализации Modbus в режиме слейв
******************************************************************************/ ******************************************************************************/
#ifndef __MODBUS_SLAVE_H_ #ifndef __MODBUS_SLAVE_H_
#define __MODBUS_SLAVE_H_ #define __MODBUS_SLAVE_H_
#include "rs_message.h" #include "rs_message.h"
#ifdef MODBUS_ENABLE_SLAVE #ifdef MODBUS_ENABLE_SLAVE
#define MODBUS_MODE_SLAVE 0
#endif
/** /**
* @addtogroup MODBUS_SLAVE * @addtogroup MODBUS_SLAVE
* @{ * @{
*/ */
/* Ответить позже, не в прерывании */
HAL_StatusTypeDef MB_Slave_ResponseLater(RS_HandleTypeDef *hmodbus, uint8_t ResponseCode);
/* Ответить на запрос */
HAL_StatusTypeDef MB_Slave_SendResponse(RS_HandleTypeDef *hmodbus, uint8_t ResponseCode, MB_ExceptionTypeDef error);
/* Ответ на сообщение в режиме слейва */ /* Ответ на сообщение в режиме слейва */
RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg); RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg);
/* Сбор сообщения в буфер UART в режиме слейв (фрейм слейва из msg -> uart) */ /* Сбор сообщения в буфер UART в режиме слейв (фрейм слейва из msg -> uart) */
@@ -33,4 +35,7 @@ RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef
/** MODBUS_SLAVE /** MODBUS_SLAVE
* @} * @}
*/ */
#endif //MODBUS_ENABLE_SLAVE
#endif //__MODBUS_SLAVE_H_ #endif //__MODBUS_SLAVE_H_

View File

@@ -1,30 +1,30 @@
/** /**
****************************************************************************** *******************************************************************************
* @file rs_message.h * @file rs_message.h
* @brief Библиотека обмена сообщениями по RS-интерфейсу * @brief Библиотека обмена сообщениями по RS-интерфейсу
****************************************************************************** *******************************************************************************
@defgroup RS_TOOLS RS Tools @defgroup RS_TOOLS RS Tools
@brief Всякое для работы по UART/RS @brief Всякое для работы по UART/RS
@{ @{
****************************************************************************** *******************************************************************************
* @details * @details
Универсальная библиотека для работы с последовательными протоколами (Modbus, Custom) Универсальная библиотека для работы с последовательными протоколами (Modbus, Custom)
через UART в режиме прерываний с поддержкой таймаутов. через UART в режиме прерываний с поддержкой таймаутов.
@section Основные возможности: @section posibility Основные возможности:
- Прием/передача в прерываниях - Прием/передача в прерываниях
- Обработка IDLE линии для определения конца фрейма - Обработка IDLE линии для определения конца фрейма
- Таймауты приема через TIM - Таймауты приема через TIM
- Гибкая настройка размера сообщений - Гибкая настройка размера сообщений
@section Использование: @section usage Использование:
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 features Особенности:
- Буфер: RS_Buffer[MSG_SIZE_MAX] Общий для приема/передачи - Буфер: RS_Buffer[RS_MSG_SIZE_MAX] Общий для приема/передачи
- Состояния: отслеживается через флаги в RS_HandleTypeDef - Состояния: отслеживается через флаги в RS_HandleTypeDef
- Таймауты: контролируют максимальное время ожидания фрейма - Таймауты: контролируют максимальное время ожидания фрейма
******************************************************************************/ ******************************************************************************/
@@ -36,8 +36,8 @@
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
////////////////////////////---DEFINES---//////////////////////////// ////////////////////////////---DEFINES---////////////////////////////
/* Check that all defines required by RS are defined */ /* Check that all defines required by RS are defined */
#ifndef MSG_SIZE_MAX #ifndef RS_MSG_SIZE_MAX
#error Define MSG_SIZE_MAX (Maximum size of message). This is necessary to create buffer for UART. #error Define RS_MSG_SIZE_MAX (Maximum size of message). This is necessary to create buffer for UART.
#endif #endif
/** /**
@@ -45,7 +45,7 @@
*/ */
/* Clear message-uart buffer */ /* Clear message-uart buffer */
#define RS_Clear_Buff(_buff_) for(int i=0; i<MSG_SIZE_MAX;i++) _buff_[i] = NULL #define RS_Clear_Buff(_buff_) for(int i=0; i<RS_MSG_SIZE_MAX;i++) _buff_[i] = NULL
/* Set/Reset flags */ /* Set/Reset flags */
#define RS_Set_Free(_hRS_) _hRS_->f.RS_Busy = 0 #define RS_Set_Free(_hRS_) _hRS_->f.RS_Busy = 0
@@ -68,7 +68,7 @@
#define RS_Set_TX_End(_hRS_) RS_Reset_TX_Flags(_hRS_); RS_Set_TX_End_Flag(_hRS_) #define RS_Set_TX_End(_hRS_) RS_Reset_TX_Flags(_hRS_); RS_Set_TX_End_Flag(_hRS_)
/* Clear all RS stuff */ /* Clear all RS stuff */
#define RS_Clear_All(_hRS_) RS_Clear_Buff(_hRS_->pBufferPtr); RS_Reset_RX_Flags(_hRS_); RS_Reset_TX_Flags(_hRS_); #define RS_Clear_All(_hRS_) RS_Clear_Buff(_hRS_->BufferPtr); RS_Reset_RX_Flags(_hRS_); RS_Reset_TX_Flags(_hRS_);
//#define MB_Is_RX_Busy(_hRS_) ((_hRS_->huart->gState&HAL_USART_STATE_BUSY_RX) == HAL_USART_STATE_BUSY_RX) //#define MB_Is_RX_Busy(_hRS_) ((_hRS_->huart->gState&HAL_USART_STATE_BUSY_RX) == HAL_USART_STATE_BUSY_RX)
//#define MB_Is_TX_Busy(_hRS_) ((_hRS_->huart->gState&HAL_USART_STATE_BUSY_RX) == HAL_USART_STATE_BUSY_TX) //#define MB_Is_TX_Busy(_hRS_) ((_hRS_->huart->gState&HAL_USART_STATE_BUSY_RX) == HAL_USART_STATE_BUSY_TX)
@@ -76,48 +76,83 @@
#define RS_Is_TX_Busy(_hRS_) (_hRS_->f.TX_Busy == 1) #define RS_Is_TX_Busy(_hRS_) (_hRS_->f.TX_Busy == 1)
#ifndef printf_rs_err
#define printf_rs_err(...)
#endif
#ifndef printf_rs
#define printf_rs(...)
#endif
#ifndef __MYLIBS_CONFIG_H_
// дефайны из mylibs include
static int dummy;
#define TrackerTypeDef(num_user_vars) void *
#define num_of_usercnts(_user_) 0
#define assert_tracecnt(_cntstruct_, _uservarnumb_) 0
#define if_assert_usertracker(_cntstruct_, _uservarnumb_) if(0)
#define tern_assert_usertracker(_cntstruct_, _uservarnumb_) 0
#define TrackerGet_Ok(_cntstruct_) dummy
#define TrackerGet_Err(_cntstruct_) dummy
#define TrackerGet_Warn(_cntstruct_) dummy
#define TrackerGet_User(_cntstruct_, _uservarnumb_) dummy
#define TrackerCnt_Ok(_cntstruct_)
#define TrackerCnt_Err(_cntstruct_)
#define TrackerCnt_Warn(_cntstruct_)
#define TrackerCnt_User(_cntstruct_, _uservarnumb_)
#define TrackerWrite_User(_cntstruct_, _uservarnumb_, _val_)
#define TrackerClear_All(_cntstruct_)
#define TrackerClear_Ok(_cntstruct_)
#define TrackerClear_Err(_cntstruct_)
#define TrackerClear_Warn(_cntstruct_)
#define TrackerClear_User(_cntstruct_)
#define TrackerClear_UserAll(_cntstruct_)
#else
#include "mylibs_include.h"
#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
#ifndef local_time
#define local_time() uwTick
#endif
/** @endcond */ /** @endcond */
/**
* @addtogroup RS_DEBUG Tools for debug RS/UART/TIM
* @ingroup RS_TOOLS
* @brief Дефайны для отладки периферии
* @{
*/
#ifndef RS_USER_VARS_NUMB
#define RS_USER_VARS_NUMB 0 ///< Количество переменных в @ref TrackerTypeDef
#endif
#ifndef TrackerTypeDef
/**
* @brief Тип структуры для счетчиков-переменных
* @param num_user_vars Есть возмоность добавления num_user_vars количества пользовательскиъх переменных
*/
#define TrackerTypeDef(num_user_vars) void *
#endif
#ifndef TrackerCnt_Ok
/** @brief Инкрементировать переменную - успешных событий */
#define TrackerCnt_Ok(_cntstruct_)
#endif
#ifndef TrackerCnt_Err
/** @brief Инкрементировать переменную - ошибок */
#define TrackerCnt_Err(_cntstruct_)
#endif
#ifndef TrackerCnt_Warn
/** @brief Инкрементировать переменную - предупреждений */
#define TrackerCnt_Warn(_cntstruct_)
#endif
#ifndef printf_rs
/** @brief Printf обычных событий RS/UART/TIM */
#define printf_rs(...)
#endif
#ifndef printf_rs_err
/** @brief Printf ошибок RS/UART/TIM */
#define printf_rs_err(...)
#endif
#ifndef RS_TIM_Handler_ENTER
/** @brief Действия при заходе в прерывания таймера */
#define RS_TIM_Handler_ENTER()
#endif
#ifndef RS_TIM_Handler_EXIT
/** @brief Действия при выходе из прерывания таймера */
#define RS_TIM_Handler_EXIT()
#endif
#ifndef RS_UART_Handler_ENTER
/** @brief Действия при заходе в прерывания UART */
#define RS_UART_Handler_ENTER()
#endif
#ifndef RS_UART_Handler_EXIT
/** @brief Действия при выходе из прерывания UART */
#define RS_UART_Handler_EXIT()
#endif
/** RS_TOOLS
* @}
*/
// направление передачи rs485 // направление передачи rs485
#ifndef RS_EnableReceive #ifndef RS_EnableReceive
#define RS_EnableReceive() ///< Функция изменения направления передачи на ПРИЕМ для RS-485 #define RS_EnableReceive() ///< Функция изменения направления передачи на ПРИЕМ для RS-485
@@ -141,9 +176,10 @@ typedef enum // RS_StatusTypeDef
/*0x03*/ RS_ABORTED, /*0x03*/ RS_ABORTED,
/*0x04*/ RS_BUSY, /*0x04*/ RS_BUSY,
/*0x05*/ RS_SKIP, /*0x05*/ RS_SKIP,
/*0x06*/ RS_TIMEOUT,
/*0x06*/ RS_COLLECT_MSG_ERR, /*0x07*/ RS_COLLECT_MSG_ERR,
/*0x07*/ RS_PARSE_MSG_ERR, /*0x08*/ RS_PARSE_MSG_ERR,
// reserved values // reserved values
// /*0x00*/ RS_UNKNOWN_ERR = 0x00, ///< reserved for case, if no one error founded (nothing changed response from zero) // /*0x00*/ RS_UNKNOWN_ERR = 0x00, ///< reserved for case, if no one error founded (nothing changed response from zero)
@@ -183,11 +219,13 @@ typedef struct
unsigned TX_Done:1; ///< 1 - Передача закончена, 0 - Передача еще в процессе или не инициализирована unsigned TX_Done:1; ///< 1 - Передача закончена, 0 - Передача еще в процессе или не инициализирована
// Выставление следующие флагов определяет пользователь // Выставление следующие флагов определяет пользователь
unsigned RX_Continue:1; ///< 0 - Продолжить принимать, 0 - Начать прием сначала unsigned RX_Continue:1; ///< 1 - Продолжить принимать, 0 - Начать прием сначала
unsigned MessageHandled:1; ///< 1 - Обработка запроса успешна, 0 - Обработка запроса в процессе или ошибка unsigned MessageHandled:1; ///< 1 - Обработка запроса успешна, 0 - Обработка запроса в процессе или ошибка
unsigned EchoResponse:1; ///< 1 - Ответить эхом, 0 - Ответить своим сообщением unsigned EchoResponse:1; ///< 1 - Ответить эхом, 0 - Ответить своим сообщением
unsigned DeferredResponse:1; ///< 1 - Не начинать передачу в IT, 0 - Ответить в прерывании unsigned DataUpdated:1; ///< 1 - Данные были обновлены:
unsigned DataUpdated:1; ///< 1 - Данные были обновлены unsigned DeviceBusy:1; ///< 1 - Устройство занято (важно! не rs а именно устрройство)
unsigned DeferredResponse:8; ///< >0 - Не начинать передачу в IT, 0 - Ответить в прерывании
}RS_FlagsTypeDef; }RS_FlagsTypeDef;
@@ -201,7 +239,7 @@ typedef struct // RS_HandleTypeDef
/* MESSAGE */ /* MESSAGE */
uint8_t ID; ///< ID хендла uint8_t ID; ///< ID хендла
RS_MsgTypeDef *pMessagePtr; ///< Указатель на структуру протокола RS_MsgTypeDef *pMessagePtr; ///< Указатель на структуру протокола
uint8_t *pBufferPtr; ///< Указатеь на буфер UART uint8_t BufferPtr[RS_MSG_SIZE_MAX]; ///< Указатеь на буфер 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 */
@@ -209,6 +247,7 @@ typedef struct // RS_HandleTypeDef
TIM_HandleTypeDef *htim; ///< Хендл TIM TIM_HandleTypeDef *htim; ///< Хендл TIM
RS_ModeTypeDef sRS_Mode; ///< Настройка: слейв/мастер @ref RS_ModeTypeDef RS_ModeTypeDef sRS_Mode; ///< Настройка: слейв/мастер @ref RS_ModeTypeDef
uint16_t sRS_Timeout; ///< Настройка: Таймаут в тиках таймера uint16_t sRS_Timeout; ///< Настройка: Таймаут в тиках таймера
void (*pSetDirection)(int Tx); ///< Указатель на функцию: смена направления
void (*pCallback)(void*, void*); ///< Указатель на коллбек: принят ответ в режиме мастер void (*pCallback)(void*, void*); ///< Указатель на коллбек: принят ответ в режиме мастер
/* FLAGS */ /* FLAGS */
@@ -252,7 +291,7 @@ RS_StatusTypeDef RS_Receive_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg); RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
/* Инициалазация структуры @ref RS_HandleTypeDef */ /* Инициалазация структуры @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, void (*pSetDirection)(int Tx));
/* Отменить прием/передачу RS/UART */ /* Отменить прием/передачу RS/UART */
RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode); RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode);

View File

@@ -10,20 +10,25 @@ Modbus/ Иерархия модулей:
│ inc/ modbus │ inc/ modbus
│ ├── modbus.h # Главный заголовочный файл modbus_slave │ ├── modbus.h # Главный заголовочный файл modbus_slave
│ ├── modbus_core.h # Базовые определения и структуры modbus_master │ ├── modbus_core.h # Базовые определения и структуры modbus_master
│ ├── modbus_coils.h # Работа с дискретными выходами ├── modbus_coils │ ├── modbus_coils.h # Работа с дискретными коилами ├── modbus_coils
│ ├── modbus_holdregs.h # Работа с регистрами хранения ├── modbus_inputregs │ ├── modbus_holdregs.h # Работа с регистрами хранения ├── modbus_inputregs
│ ├── modbus_inputregs.h # Работа с входными регистрами ├── modbus_inputregs │ ├── modbus_inputregs.h # Работа с входными регистрами ├── modbus_inputregs
│ ├── modbus_devid.h # Идентификация устройства ├── modbus_devid │ ├── modbus_devid.h # Идентификаторы устройства ├── modbus_devid
│ ├── rs_message.h # Драйвер обмена по RS/UART ├── modbus_diag │ ├── modbus_master.h # Заголовочный файл Master режима ├── modbus_diag
├── src/ └── rs_message │ ├── modbus_slave.h # Заголовочный файл Slave режима ├── modbus_oscil
│ ├── modbus.c # Основная логика Modbus │ │ ├── modbus_diag.h # Диагностика Modbus └── rs_message
│ ├── modbus_slave.c # Основная логика Slave Modbus └── modbus_core (единое ядро) │ ├── modbus_oscil.h # Осциллографирование данных │
── modbus_master.c # Основная логика Master Modbus ├── modbus_config ── rs_message.h # Драйвер обмена по RS/UART └── modbus_core (единое ядро)
│ ├── modbus_coils.c # Реализация работы с coils ├── modbus_data ├── src/ ├── modbus_config
│ ├── modbus_holdregs.c # Реализация регистров хранения └── __crc_algs │ ├── modbus.c # Основная логика Modbus ├── modbus_data
│ ├── modbus_slave.c # Основная логика Slave Modbus └── __crc_algs
│ ├── modbus_master.c # Основная логика Master Modbus
│ ├── modbus_coils.c # Реализация работы с coils
│ ├── modbus_holdregs.c # Реализация регистров хранения
│ ├── modbus_inputregs.c # Реализация входных регистров │ ├── modbus_inputregs.c # Реализация входных регистров
│ ├── modbus_devid.c # Реализация идентификации устройства │ ├── modbus_devid.c # Реализация идентификации устройства
│ ├── modbus_data.c # Функции доступа к данным │ ├── modbus_diag.c # Диагностические функции и счетчики ошибок
│ ├── modbus_oscil.c # Сбор и хранение осциллограмм
│ └── rs_message.c # Реализация драйвера RS │ └── rs_message.c # Реализация драйвера RS
├── __modbus_config.h # Конфигурация Modbus (надо заменить) ├── __modbus_config.h # Конфигурация Modbus (надо заменить)
├── __modbus_data.h # Структуры данных (надо заменить) ├── __modbus_data.h # Структуры данных (надо заменить)
@@ -32,14 +37,14 @@ Modbus/ Иерархия модулей:
## Инструкция по подключению ## Инструкция по подключению
1. **Склонируйте субмодуль** в ваш проект: ### 1. **Склонируйте субмодуль** в ваш проект:
```bash ```bash
git submodule add https://git.arktika.cyou/set506/STM32_Modbus path/to/Modbus git submodule add https://git.arktika.cyou/set506/STM32_Modbus path/to/Modbus
git submodule update --init --recursive git submodule update --init --recursive
``` ```
2. **Скопируйте файлы конфигурации** в отдельную папку в вашем проекте (вне субмодуля) и удалите `__` из имени файлов: ### 2. **Скопируйте файлы конфигурации** в отдельную папку в вашем проекте (вне субмодуля) и удалите `__` из имени файлов:
``` ```
ProjectRoot/ ProjectRoot/
@@ -50,18 +55,16 @@ ProjectRoot/
└── Modbus/ # Субмодуль └── Modbus/ # Субмодуль
``` ```
3. **Настройте конфигурацию** под ваш проект: ### 3. **Настройте конфигурацию** под ваш проект:
#### 3.1. Настройка периферии
3.1. Настройка периферии
- **UART**: Настройте в режиме Asynchronous, нужная скорость (9600, 19200, etc), 8N1 - **UART**: Настройте в режиме Asynchronous, нужная скорость (9600, 19200, etc), 8N1
- **TIM**: Настройте таймер для генерации прерываний (например, 1ms tick) - **TIM**: Настройте таймер для генерации прерываний (например, 1ms tick)
- **Включите прерывания** для UART и TIM - **Включите прерывания** для UART и TIM
3.2. Подключение обработчиков прерываний #### 3.2. Подключение обработчиков прерываний
Подключите обработчики прерываний **UART** и **TIM** в свои IRQ обработчики ***вместо*** HAL-обработчиков: Подключите обработчики прерываний **UART** и **TIM** в свои IRQ обработчики ***вместо*** HAL-обработчиков:
```c ```c
#include "modbus.h" #include "modbus.h"
@@ -79,16 +82,21 @@ ProjectRoot/
HAL_TIM_IRQHandler(&htim); HAL_TIM_IRQHandler(&htim);
} }
``` ```
#### 3.3. В `modbus_config.h` укажите параметры устройства
3.3. В `modbus_config.h` укажите параметры устройства #### 3.4. Инициализация в коде
3.4. Инициализация в коде
Чтобы настроить Slave-режим `main()` после инициализации HAL: Чтобы настроить Slave-режим `main()` после инициализации HAL:
```c ```c
#include "modbus.h" #include "modbus.h"
// TxEnable: 1 - передача, 0 - прием
void SetTxDirectionFunc(int TxEnable)
{
HAL_GPIO_WritePin(SCIDE1_GPIO_Port, SCIDE1_Pin, !TxEnable);
}
int main(void) int main(void)
{ {
// Инициализация HAL // Инициализация HAL
@@ -99,7 +107,7 @@ ProjectRoot/
MX_TIM3_Init(); MX_TIM3_Init();
// Инициализация Modbus // Инициализация Modbus
MODBUS_FirstInit(&hmodbus1, &mb_huart, &mb_htim); MODBUS_FirstInit(&hmodbus1, &mb_huart, &mb_htim, &SetTxDirectionFunc);
MODBUS_Config(&hmodbus1, MODBUS_DEVICE_ID, MODBUS_TIMEOUT, MODBUS_MODE_SLAVE); MODBUS_Config(&hmodbus1, MODBUS_DEVICE_ID, MODBUS_TIMEOUT, MODBUS_MODE_SLAVE);
// Запуск приема Modbus // Запуск приема Modbus
@@ -111,20 +119,32 @@ ProjectRoot/
} }
} }
``` ```
Чтобы настроить Master-режим `main()` после инициализации HAL: Чтобы настроить Master-режим `main()` после инициализации HAL:
```c ```c
#include "modbus.h" #include "modbus.h"
// Инициализация Modbus
MODBUS_FirstInit(&hmodbus1, &mb_huart, &mb_htim, &SetTxDirectionFunc);
MODBUS_Config(&hmodbus1, 0, MODBUS_TIMEOUT, MODBUS_MODE_MASTER);
// Запрос на 1 ID, считать холдинг регистры с 0 адреса 10 штук // Запрос на 1 ID, считать холдинг регистры с 0 адреса 10 штук
RS_MsgTypeDef read_hold_cmd = MB_MASTER_READ_HOLDING_REGS(1, 0, 10); // При получении ответа вызовется функция callback_func()
RS_MsgTypeDef msg = MB_REQUEST_READ_HOLDING_REGS(1, 0, 10);
MODBUS_MasterRequest(&hmodbus1, &msg, &callback_func);
// коллбек, вызовется при получении ответа от слейва // коллбек, вызовется при получении ответа от слейва
read_hold[10]; read_hold[10];
void callback_func(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) void callback_func(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
{ {
// MB_RespGet_... Чтобы достать нужные данные из ответа // MB_RespGet_... Чтобы достать нужные данные из ответа
if(hmodbus->RS_STATUS == RS_OK) // Получен ответ без ошибок
{
for(int addr = MODBUS_MSG.Addr; addr < MODBUS_MSG.Addr + MODBUS_MSG.Qnt; addr++) for(int addr = MODBUS_MSG.Addr; addr < MODBUS_MSG.Addr + MODBUS_MSG.Qnt; addr++)
{ {
// Запись регистров из ответа в массив
uint16_t value; uint16_t value;
if(MB_RespGet_RegisterValue(&MODBUS_MSG, addr, &value)) if(MB_RespGet_RegisterValue(&MODBUS_MSG, addr, &value))
{ {
@@ -132,6 +152,11 @@ ProjectRoot/
} }
} }
} }
else // Ответ получен с ошибкой или не получен вовсе
{
}
}
int main(void) int main(void)
{ {
// Инициализация HAL // Инициализация HAL
@@ -150,7 +175,7 @@ ProjectRoot/
} }
``` ```
3.5. Настройка карты данных #### 3.5. Настройка карты данных (только для режима Slave)
В `modbus_data.h` настройте регистры и coils под ваше устройство: В `modbus_data.h` настройте регистры и coils под ваше устройство:
@@ -167,7 +192,6 @@ ProjectRoot/
#define R_INPUT_ADDR 0 // Начальный адрес Input регистров #define R_INPUT_ADDR 0 // Начальный адрес Input регистров
#define R_INPUT_QNT 4 // Количество Input регистров #define R_INPUT_QNT 4 // Количество Input регистров
``` ```
**Holding Registers (чтение/запись)** **Holding Registers (чтение/запись)**
```c ```c
typedef struct typedef struct
@@ -180,7 +204,6 @@ ProjectRoot/
#define R_HOLDING_ADDR 0 // Начальный адрес Holding регистров #define R_HOLDING_ADDR 0 // Начальный адрес Holding регистров
#define R_HOLDING_QNT 3 // Количество Holding регистров #define R_HOLDING_QNT 3 // Количество Holding регистров
``` ```
**Coils (1-битные)** **Coils (1-битные)**
```c ```c
typedef struct typedef struct
@@ -195,11 +218,9 @@ ProjectRoot/
#define C_COILS_ADDR 0 // Начальный адрес Coils #define C_COILS_ADDR 0 // Начальный адрес Coils
#define C_COILS_QNT 4 // Количество Coils #define C_COILS_QNT 4 // Количество Coils
``` ```
#### 3.6. Доступ к данным в коде
3.6. Доступ к данным в коде В режиме **слейва** есть дефайны для удобного выставления Коилов. На случай если они не упакованы в битовые поля
В режиме слейва есть дефайны для удобного выставления Коилов. На случай если они не упакованы в битовые поля
```c ```c
// Чтение входных регистров // Чтение входных регистров
uint16_t temp = MB_DATA.InRegs.Temperature; uint16_t temp = MB_DATA.InRegs.Temperature;
@@ -208,16 +229,15 @@ ProjectRoot/
MB_DATA.HoldRegs.SetpointTemp = 2500; MB_DATA.HoldRegs.SetpointTemp = 2500;
// Управление coils // Управление coils
MB_Coil_Set_Local(&MB_DATA.Coils, 0); // Включить Relay1 MB_Coil_Set_Local(&MB_DATA.Coils, 0); // Включить 0 бит в Coils
MB_Coil_Reset_Local(&MB_DATA.Coils, 1); // Выключить Relay2 MB_Coil_Reset_Local(&MB_DATA.Coils, 1); // Выключить 1 бит в Coils
// Чтение coil // Чтение coil
if (MB_Coil_Read_Local(&MB_DATA.Coils, 2)) { if (MB_Coil_Read_Local(&MB_DATA.Coils, 2)) {
// Pump включен // Pump включен
} }
``` ```
В режиме **мастера** есть функции для получения информации из ответа `MB_RespGet_...()`
В режиме мастера есть функции для получения информации из ответа `MB_RespGet_...()`
```c ```c
// Чтение регистров: Получить запрошенные регистры // Чтение регистров: Получить запрошенные регистры
uint16_t value; uint16_t value;
@@ -255,8 +275,7 @@ ProjectRoot/
5. **Обновление библиотеки**: ### 5. **Обновление библиотеки**:
После обновления субмодуля из Git, исходные файлы библиотеки будут обновлены, и ваши конфиги вне субмодуля не перезапишутся: После обновления субмодуля из Git, исходные файлы библиотеки будут обновлены, и ваши конфиги вне субмодуля не перезапишутся:
```bash ```bash

7
Src/__modbus_compat.c Normal file
View File

@@ -0,0 +1,7 @@
/**
*******************************************************************************
* @file __modbus_compat.c
* @brief Модуль для совместимости библиотеки MODBUS.
*******************************************************************************
******************************************************************************/
#include "modbus.h"

View File

@@ -1,12 +1,12 @@
/** /**
************************************************************************** *******************************************************************************
* @file modbus.c * @file modbus.c
* @brief Модуль для реализации MODBUS. * @brief Модуль для реализации MODBUS.
************************************************************************** *******************************************************************************
* @details * @details
Файл содержит реализацию функций работы с Modbus. Файл содержит реализацию функций работы с Modbus.
@section Функции и макросы @section mbapi Функции и макросы
### Инициализация: ### Инициализация:
- MODBUS_FirstInit() — Инициализация Modbus (подключение UART, TIM) - MODBUS_FirstInit() — Инициализация Modbus (подключение UART, TIM)
@@ -24,8 +24,6 @@
RS_HandleTypeDef hmodbus1; ///< Default Handle for Modbus RS_HandleTypeDef hmodbus1; ///< Default Handle for Modbus
RS_MsgTypeDef MODBUS_MSG; ///< Default Message Struct for Modbus RS_MsgTypeDef MODBUS_MSG; ///< Default Message Struct for Modbus
/* DEFINE DATA FOR MODBUS */
MB_DataStructureTypeDef MB_DATA = {0};; ///< Coils & Registers
static void MB_DefaultCallback(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg); static void MB_DefaultCallback(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg);
@@ -36,10 +34,11 @@ static void MB_DefaultCallback(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_
* @param hmodbus Указатель на хендлер RS * @param hmodbus Указатель на хендлер RS
* @param huart Указатель на хендлер UART * @param huart Указатель на хендлер UART
* @param htim Указатель на хендлер TIM * @param htim Указатель на хендлер TIM
* @param pSetDirection Указатель на функцию для смены направления RS485
* @details Подключает хендлы периферии к hmodbus * @details Подключает хендлы периферии к hmodbus
* Конфигурация выставляется по умолчанию из modbus_config.h * Конфигурация выставляется по умолчанию из modbus_config.h
*/ */
HAL_StatusTypeDef MODBUS_FirstInit(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim) HAL_StatusTypeDef MODBUS_FirstInit(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, void (*pSetDirection)(int Tx))
{ {
if((hmodbus == NULL) || (huart == NULL)) if((hmodbus == NULL) || (huart == NULL))
{ {
@@ -53,9 +52,10 @@ HAL_StatusTypeDef MODBUS_FirstInit(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef
hmodbus->sRS_Mode = RS_SLAVE_ALWAYS_WAIT; hmodbus->sRS_Mode = RS_SLAVE_ALWAYS_WAIT;
// INIT // INIT
hmodbus->RS_STATUS = RS_Init(hmodbus, huart, htim, 0); hmodbus->RS_STATUS = RS_Init(hmodbus, huart, htim, pSetDirection);
RS_EnableReceive(); if(hmodbus->pSetDirection)
hmodbus->pSetDirection(0);
if(hmodbus->RS_STATUS == RS_OK) if(hmodbus->RS_STATUS == RS_OK)
return HAL_OK; return HAL_OK;
@@ -164,9 +164,15 @@ HAL_StatusTypeDef MODBUS_MasterRequest(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef
return HAL_ERROR; return HAL_ERROR;
} }
//-------------------------------------------------------------------
//-----------------------------INTERNAL------------------------------
/**
* @brief Дефолтный коллбек для мастера.
* @param hmodbus Указатель на хендлер RS
* @param modbus_msg Указатель на структуру сообщения
* @details В этот коллбек попадут все запросы, с NULL-коллбеком
*/
static void MB_DefaultCallback(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) static void MB_DefaultCallback(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg)
{ {
__NOP(); __NOP();

View File

@@ -1,14 +1,22 @@
/** /**
****************************************************************************** *******************************************************************************
* @file modbus_coils.c * @file modbus_coils.c
* @brief Реализация работы с коилами Modbus * @brief Реализация работы с коилами Modbus
****************************************************************************** *******************************************************************************
* @details * @details
Модуль для доступа к coils внутри программы:
- Функции для доступа к coils по глобальным адресам
- Макросы для доступа к coils по локальным адресам
Модуль обработки команд для coils (битовых данных): Модуль обработки команд для coils (битовых данных):
- Чтение coils (0x01) - упаковка битов в байты для передачи - Чтение coils (0x01) - упаковка битов в байты для передачи
- Запись одиночного coil (0x05) - установка/сброс бита - Запись одиночного coil (0x05) - установка/сброс бита
- Запись множественных coils (0x0F) - распаковка битов из байтов - Запись множественных coils (0x0F) - распаковка битов из байтов
@section cvalid Валидация данных:
- Проверка соответствия количества байт и регистров
- Валидация адресов через MB_DefineRegistersAddress()
- Обработка исключений при некорректных запросах
******************************************************************************/ ******************************************************************************/
#include "modbus_coils.h" #include "modbus_coils.h"
@@ -18,7 +26,7 @@
* @brief Выставить/сбросить коил по глобальному адресу. * @brief Выставить/сбросить коил по глобальному адресу.
* @param Addr Адрес коила. * @param Addr Адрес коила.
* @param WriteVal Что записать в коил: 0 или 1. * @param WriteVal Что записать в коил: 0 или 1.
* @return ExceptionCode Код исключения если коила по адресу не существует, и NO_ERRORS если все ок. * @return ExceptionCode Код исключения если коила по адресу не существует, и ET_NO_ERRORS если все ок.
* *
* @details Позволяет обратиться к любому коилу по его глобальному адрессу. * @details Позволяет обратиться к любому коилу по его глобальному адрессу.
Вне зависимости от того как коилы размещены в памяти. Вне зависимости от того как коилы размещены в памяти.
@@ -26,13 +34,13 @@
MB_ExceptionTypeDef MB_Coil_Write_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 = ET_NO_ERRORS;
uint16_t *coils; uint16_t *coils;
uint16_t start_shift = 0; // shift in coils register uint16_t start_shift = 0; // shift in coils register
//------------WRITE COIL------------- //------------WRITE COIL-------------
Exception = MB_DefineCoilsAddress(&coils, Addr, 1, &start_shift, 1); Exception = MB_DefineCoilsAddress(&coils, Addr, 1, &start_shift, 1);
if(Exception == NO_ERRORS) if(Exception == ET_NO_ERRORS)
{ {
switch(WriteVal) switch(WriteVal)
{ {
@@ -57,7 +65,7 @@ MB_ExceptionTypeDef MB_Coil_Write_Global(uint16_t Addr, MB_CoilsOpTypeDef WriteV
/** /**
* @brief Считать коил по глобальному адресу. * @brief Считать коил по глобальному адресу.
* @param Addr Адрес коила. * @param Addr Адрес коила.
* @param Exception Указатель на переменную для кода исключения, в случа неудачи при чтении. * @param Exception Указатель на переменную для кода исключения, в случае неудачи при чтении.
* @return uint16_t Возвращает весь регистр с маской на запрошенном коиле. * @return uint16_t Возвращает весь регистр с маской на запрошенном коиле.
* *
* @details Позволяет обратиться к любому коилу по его глобальному адрессу. * @details Позволяет обратиться к любому коилу по его глобальному адрессу.
@@ -75,7 +83,7 @@ uint16_t MB_Coil_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception)
//------------READ COIL-------------- //------------READ COIL--------------
*Exception = MB_DefineCoilsAddress(&coils, Addr, 1, &start_shift, 0); *Exception = MB_DefineCoilsAddress(&coils, Addr, 1, &start_shift, 0);
if(*Exception == NO_ERRORS) if(*Exception == ET_NO_ERRORS)
{ {
return ((*coils)&(1<<start_shift)); return ((*coils)&(1<<start_shift));
} }
@@ -86,51 +94,6 @@ uint16_t MB_Coil_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception)
} }
/**
* @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). * @brief Обработать функцию Read Coils (01 - 0x01).
* @param modbus_msg Указатель на структуру собщения modbus. * @param modbus_msg Указатель на структуру собщения modbus.
@@ -144,7 +107,7 @@ uint8_t MB_Process_Read_Coils(RS_MsgTypeDef *modbus_msg)
uint16_t start_shift = 0; // shift in coils register uint16_t start_shift = 0; // shift in coils register
modbus_msg->Except_Code = MB_DefineCoilsAddress(&coils, modbus_msg->Addr, modbus_msg->Qnt, &start_shift, 0); modbus_msg->Except_Code = MB_DefineCoilsAddress(&coils, modbus_msg->Addr, modbus_msg->Qnt, &start_shift, 0);
if(modbus_msg->Except_Code != NO_ERRORS) if(modbus_msg->Except_Code != ET_NO_ERRORS)
return 0; return 0;
//-----------READING COIL------------ //-----------READING COIL------------
@@ -172,14 +135,14 @@ uint8_t MB_Process_Read_Coils(RS_MsgTypeDef *modbus_msg)
shift = 0; // set shift to zero for the next step shift = 0; // set shift to zero for the next step
//-----------READ COILS-------------- //-----------READ COILS--------------
modbus_msg->DATA[ind] = (*(coils+ind)&mask_for_coils) >> start_shift; modbus_msg->MbData[ind] = (*(coils+ind)&mask_for_coils) >> start_shift;
if(ind > 0) if(ind > 0)
modbus_msg->DATA[ind-1] |= ((*(coils+ind)&mask_for_coils) << 16) >> start_shift; modbus_msg->MbData[ind-1] |= ((*(coils+ind)&mask_for_coils) << 16) >> start_shift;
} }
// т.к. DATA 16-битная, для 8-битной передачи, надо поменять местами верхний и нижний байты // т.к. MbData 16-битная, для 8-битной передачи, надо поменять местами верхний и нижний байты
for(; ind >= 0; --ind) for(; ind >= 0; --ind)
modbus_msg->DATA[ind] = ByteSwap16(modbus_msg->DATA[ind]); modbus_msg->MbData[ind] = ByteSwap16(modbus_msg->MbData[ind]);
return 1; return 1;
} }
@@ -195,14 +158,14 @@ 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))
{ {
modbus_msg->Except_Code = ILLEGAL_DATA_VALUE; modbus_msg->Except_Code = ET_ILLEGAL_DATA_VALUE;
return 0; return 0;
} }
// define position of coil // define position of coil
uint16_t *coils; uint16_t *coils;
uint16_t start_shift = 0; // shift in coils register uint16_t start_shift = 0; // shift in coils register
modbus_msg->Except_Code = MB_DefineCoilsAddress(&coils, modbus_msg->Addr, 0, &start_shift, 1); modbus_msg->Except_Code = MB_DefineCoilsAddress(&coils, modbus_msg->Addr, 0, &start_shift, 1);
if(modbus_msg->Except_Code != NO_ERRORS) if(modbus_msg->Except_Code != ET_NO_ERRORS)
return 0; return 0;
@@ -226,14 +189,14 @@ 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))
{ // if quantity too large OR if quantity and bytes count arent match { // if quantity too large OR if quantity and bytes count arent match
modbus_msg->Except_Code = ILLEGAL_DATA_VALUE; modbus_msg->Except_Code = ET_ILLEGAL_DATA_VALUE;
return 0; return 0;
} }
// define position of coil // define position of coil
uint16_t *coils; // pointer to coils uint16_t *coils; // pointer to coils
uint16_t start_shift = 0; // shift in coils register uint16_t start_shift = 0; // shift in coils register
modbus_msg->Except_Code = MB_DefineCoilsAddress(&coils, modbus_msg->Addr, modbus_msg->Qnt, &start_shift, 1); modbus_msg->Except_Code = MB_DefineCoilsAddress(&coils, modbus_msg->Addr, modbus_msg->Qnt, &start_shift, 1);
if(modbus_msg->Except_Code != NO_ERRORS) if(modbus_msg->Except_Code != ET_NO_ERRORS)
return 0; return 0;
//----------WRITTING COILS----------- //----------WRITTING COILS-----------
@@ -263,10 +226,10 @@ uint8_t MB_Process_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg)
// get current coils // get current coils
temp_reg = *(coils+ind); temp_reg = *(coils+ind);
// set coils // set coils
setted_coils = ByteSwap16(modbus_msg->DATA[ind]) << start_shift; setted_coils = ByteSwap16(modbus_msg->MbData[ind]) << start_shift;
if(ind > 0) if(ind > 0)
{ {
setted_coils |= ((ByteSwap16(modbus_msg->DATA[ind-1]) << start_shift) >> 16); setted_coils |= ((ByteSwap16(modbus_msg->MbData[ind-1]) << start_shift) >> 16);
} }
// write coils // write coils
@@ -281,14 +244,5 @@ uint8_t MB_Process_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg)
return 1; return 1;
} }
#else //MODBUS_ENABLE_COILS
#endif //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

View File

@@ -1,8 +1,8 @@
/** /**
****************************************************************************** *******************************************************************************
* @file modbus_core.c * @file modbus_core.c
* @brief Базовая реализация ядра Modbus (заглушка) * @brief Базовая реализация ядра Modbus
****************************************************************************** *******************************************************************************
* @details * @details
В текущей реализации этот файл служит заглушкой для будущего расширения В текущей реализации этот файл служит заглушкой для будущего расширения
функциональности ядра Modbus протокола. функциональности ядра Modbus протокола.

View File

@@ -1,15 +1,15 @@
/** /**
****************************************************************************** *******************************************************************************
* @file modbus_devid.c * @file modbus_devid.c
* @brief Реализация идентификаторов устройства Modbus * @brief Реализация идентификаторов устройства Modbus
****************************************************************************** *******************************************************************************
* @details * @details
Модуль обработки запросов идентификации устройства через MEI-тип 0x0E: Модуль обработки запросов идентификации устройства через MEI-тип 0x0E:
- Формирование иерархии объектов идентификации - Формирование иерархии объектов идентификации
- Поддержка потоковой передачи при большом количестве объектов - Поддержка потоковой передачи при большом количестве объектов
- Автоматический расчет MoreFollows флагов - Автоматический расчет MoreFollows флагов
@section Потоковая передача: @section stream Потоковая передача:
При большом количестве объектов идентификация разбивается на несколько При большом количестве объектов идентификация разбивается на несколько
сообщений с установкой флага MoreFollows и указанием NextObjId для сообщений с установкой флага MoreFollows и указанием NextObjId для
продолжения чтения в следующем запросе. продолжения чтения в следующем запросе.
@@ -21,132 +21,6 @@
MB_DeviceIdentificationsTypeDef MB_DEVID; ///< Глобальная структура идентификаторов устройства 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;
}
/** /**
@@ -173,18 +47,24 @@ void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj)
{ {
MB_DeviceObjectTypeDef *obj = (MB_DeviceObjectTypeDef *)&MB_DEVID; MB_DeviceObjectTypeDef *obj = (MB_DeviceObjectTypeDef *)&MB_DEVID;
unsigned objidtmp = modbus_msg->DevId.NextObjId; unsigned objidtmp = modbus_msg->DevId.NextObjId;
modbus_msg->Except_Code = ET_NO_ERRORS;
/* Define number of object in one message */ /* Define number of object in one message */
unsigned lastobjid = 0; unsigned lastobjid = 0;
for(int i = 0; i < DATA_SIZE*2;) for(int i = 0; i < MbData_size*2;)
{ {
/* Если объект за пределами допутимого - выходим из цикла */
if(objidtmp >= 0xFF + MODBUS_NUMB_OF_USEROBJECTS)
break;
i += 2; i += 2;
i += obj[objidtmp].length; i += obj[objidtmp].length;
/* Если все еще помещается в массив переходим на следующий объект */ /* Если все еще помещается в массив переходим на следующий объект */
if(i < DATA_SIZE*2) if(i < MbData_size*2)
{ {
objidtmp++; objidtmp++;
} }
/* Если объекты для записи закончились - выходим из цикла*/ /* Если объекты для записи закончились - выходим из цикла*/
if(objidtmp > maxidofobj) if(objidtmp > maxidofobj)
break; break;
@@ -193,7 +73,7 @@ void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj)
/* Fill message with objects data */ /* Fill message with objects data */
char *mbdata = (char *)&modbus_msg->DATA; char *mbdata = (char *)&modbus_msg->MbData;
unsigned ind = 0; unsigned ind = 0;
unsigned objid = modbus_msg->DevId.NextObjId; unsigned objid = modbus_msg->DevId.NextObjId;
for(; objid <= lastobjid; objid++) for(; objid <= lastobjid; objid++)
@@ -202,6 +82,9 @@ void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj)
MB_WriteSingleObjectToMessage(mbdata, &ind, &obj[objid]); MB_WriteSingleObjectToMessage(mbdata, &ind, &obj[objid]);
} }
objid--; objid--;
if(modbus_msg->ByteCnt != 0)
{
modbus_msg->ByteCnt = ind; modbus_msg->ByteCnt = ind;
modbus_msg->DevId.NextObjId = lastobjid+1; modbus_msg->DevId.NextObjId = lastobjid+1;
if(objid == maxidofobj) if(objid == maxidofobj)
@@ -213,6 +96,11 @@ void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj)
modbus_msg->DevId.MoreFollows = 0xFF; modbus_msg->DevId.MoreFollows = 0xFF;
} }
} }
else
{
modbus_msg->Except_Code = ET_ILLEGAL_DATA_VALUE;
}
}
/** /**
@@ -223,9 +111,11 @@ void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj)
*/ */
uint8_t MB_Process_Read_Device_Identifications(RS_MsgTypeDef *modbus_msg) uint8_t MB_Process_Read_Device_Identifications(RS_MsgTypeDef *modbus_msg)
{ {
modbus_msg->DevId.Conformity = MODBUS_DEVICE_CONFORMITY;
switch(modbus_msg->DevId.ReadDevId) switch(modbus_msg->DevId.ReadDevId)
{ {
case MB_BASIC_IDENTIFICATIONS: case RID_BASIC_IDENTIFICATIONS:
if (modbus_msg->DevId.NextObjId == 0) if (modbus_msg->DevId.NextObjId == 0)
{ {
modbus_msg->DevId.NextObjId = 0; modbus_msg->DevId.NextObjId = 0;
@@ -235,7 +125,7 @@ uint8_t MB_Process_Read_Device_Identifications(RS_MsgTypeDef *modbus_msg)
modbus_msg->DevId.NumbOfObj = 3; modbus_msg->DevId.NumbOfObj = 3;
break; break;
case MB_REGULAR_IDENTIFICATIONS: case RID_REGULAR_IDENTIFICATIONS:
if (modbus_msg->DevId.NextObjId == 0) if (modbus_msg->DevId.NextObjId == 0)
{ {
modbus_msg->DevId.NextObjId = 3; modbus_msg->DevId.NextObjId = 3;
@@ -245,10 +135,11 @@ uint8_t MB_Process_Read_Device_Identifications(RS_MsgTypeDef *modbus_msg)
modbus_msg->DevId.NumbOfObj = 4; modbus_msg->DevId.NumbOfObj = 4;
break; break;
case MB_EXTENDED_IDENTIFICATIONS: case RID_EXTENDED_IDENTIFICATIONS:
if(MODBUS_NUMB_OF_USEROBJECTS <= 0 || MODBUS_NUMB_OF_USEROBJECTS > 128) if(MODBUS_NUMB_OF_USEROBJECTS <= 0 || MODBUS_NUMB_OF_USEROBJECTS > 128)
{ {
return 0; modbus_msg->Except_Code = ET_ILLEGAL_DATA_VALUE;
break;
} }
if (modbus_msg->DevId.NextObjId == 0) if (modbus_msg->DevId.NextObjId == 0)
@@ -260,15 +151,23 @@ uint8_t MB_Process_Read_Device_Identifications(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_IDENTIFICATIONS: case RID_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;
default: default:
return 0; return 0;
} }
if(modbus_msg->Except_Code != ET_NO_ERRORS)
{
return 0;
}
else
{
return 1; return 1;
} }
}
@@ -284,402 +183,391 @@ void MB_DeviceInentificationInit(void)
MB_ObjectInit(&MB_DEVID.ProductName, MODBUS_PRODUCT_NAME); MB_ObjectInit(&MB_DEVID.ProductName, MODBUS_PRODUCT_NAME);
MB_ObjectInit(&MB_DEVID.ModelName, MODBUS_MODEL_NAME); MB_ObjectInit(&MB_DEVID.ModelName, MODBUS_MODEL_NAME);
#ifdef MODBUS_USEROBJECT_0_NAME #if defined(MODBUS_USEROBJECT_0_NAME) && MODBUS_NUMB_OF_USEROBJECTS>0
MB_ObjectInit(&MB_DEVID.User[0], MODBUS_USEROBJECT_0_NAME); MB_ObjectInit(&MB_DEVID.User[0], MODBUS_USEROBJECT_0_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_1_NAME #if defined(MODBUS_USEROBJECT_1_NAME) && MODBUS_NUMB_OF_USEROBJECTS>1
MB_ObjectInit(&MB_DEVID.User[1], MODBUS_USEROBJECT_1_NAME); MB_ObjectInit(&MB_DEVID.User[1], MODBUS_USEROBJECT_1_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_2_NAME #if defined(MODBUS_USEROBJECT_2_NAME) && MODBUS_NUMB_OF_USEROBJECTS>2
MB_ObjectInit(&MB_DEVID.User[2], MODBUS_USEROBJECT_2_NAME); MB_ObjectInit(&MB_DEVID.User[2], MODBUS_USEROBJECT_2_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_3_NAME #if defined(MODBUS_USEROBJECT_3_NAME) && MODBUS_NUMB_OF_USEROBJECTS>3
MB_ObjectInit(&MB_DEVID.User[3], MODBUS_USEROBJECT_3_NAME); MB_ObjectInit(&MB_DEVID.User[3], MODBUS_USEROBJECT_3_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_4_NAME #if defined(MODBUS_USEROBJECT_4_NAME) && MODBUS_NUMB_OF_USEROBJECTS>4
MB_ObjectInit(&MB_DEVID.User[4], MODBUS_USEROBJECT_4_NAME); MB_ObjectInit(&MB_DEVID.User[4], MODBUS_USEROBJECT_4_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_5_NAME #if defined(MODBUS_USEROBJECT_5_NAME) && MODBUS_NUMB_OF_USEROBJECTS>5
MB_ObjectInit(&MB_DEVID.User[5], MODBUS_USEROBJECT_5_NAME); MB_ObjectInit(&MB_DEVID.User[5], MODBUS_USEROBJECT_5_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_6_NAME #if defined(MODBUS_USEROBJECT_6_NAME) && MODBUS_NUMB_OF_USEROBJECTS>6
MB_ObjectInit(&MB_DEVID.User[6], MODBUS_USEROBJECT_6_NAME); MB_ObjectInit(&MB_DEVID.User[6], MODBUS_USEROBJECT_6_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_7_NAME #if defined(MODBUS_USEROBJECT_7_NAME) && MODBUS_NUMB_OF_USEROBJECTS>7
MB_ObjectInit(&MB_DEVID.User[7], MODBUS_USEROBJECT_7_NAME); MB_ObjectInit(&MB_DEVID.User[7], MODBUS_USEROBJECT_7_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_8_NAME #if defined(MODBUS_USEROBJECT_8_NAME) && MODBUS_NUMB_OF_USEROBJECTS>8
MB_ObjectInit(&MB_DEVID.User[8], MODBUS_USEROBJECT_8_NAME); MB_ObjectInit(&MB_DEVID.User[8], MODBUS_USEROBJECT_8_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_9_NAME #if defined(MODBUS_USEROBJECT_9_NAME) && MODBUS_NUMB_OF_USEROBJECTS>9
MB_ObjectInit(&MB_DEVID.User[9], MODBUS_USEROBJECT_9_NAME); MB_ObjectInit(&MB_DEVID.User[9], MODBUS_USEROBJECT_9_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_10_NAME #if defined(MODBUS_USEROBJECT_10_NAME) && MODBUS_NUMB_OF_USEROBJECTS>10
MB_ObjectInit(&MB_DEVID.User[10], MODBUS_USEROBJECT_10_NAME); MB_ObjectInit(&MB_DEVID.User[10], MODBUS_USEROBJECT_10_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_11_NAME #if defined(MODBUS_USEROBJECT_11_NAME) && MODBUS_NUMB_OF_USEROBJECTS>11
MB_ObjectInit(&MB_DEVID.User[11], MODBUS_USEROBJECT_11_NAME); MB_ObjectInit(&MB_DEVID.User[11], MODBUS_USEROBJECT_11_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_12_NAME #if defined(MODBUS_USEROBJECT_12_NAME) && MODBUS_NUMB_OF_USEROBJECTS>12
MB_ObjectInit(&MB_DEVID.User[12], MODBUS_USEROBJECT_12_NAME); MB_ObjectInit(&MB_DEVID.User[12], MODBUS_USEROBJECT_12_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_13_NAME #if defined(MODBUS_USEROBJECT_13_NAME) && MODBUS_NUMB_OF_USEROBJECTS>13
MB_ObjectInit(&MB_DEVID.User[13], MODBUS_USEROBJECT_13_NAME); MB_ObjectInit(&MB_DEVID.User[13], MODBUS_USEROBJECT_13_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_14_NAME #if defined(MODBUS_USEROBJECT_14_NAME) && MODBUS_NUMB_OF_USEROBJECTS>14
MB_ObjectInit(&MB_DEVID.User[14], MODBUS_USEROBJECT_14_NAME); MB_ObjectInit(&MB_DEVID.User[14], MODBUS_USEROBJECT_14_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_15_NAME #if defined(MODBUS_USEROBJECT_15_NAME) && MODBUS_NUMB_OF_USEROBJECTS>15
MB_ObjectInit(&MB_DEVID.User[15], MODBUS_USEROBJECT_15_NAME); MB_ObjectInit(&MB_DEVID.User[15], MODBUS_USEROBJECT_15_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_16_NAME #if defined(MODBUS_USEROBJECT_16_NAME) && MODBUS_NUMB_OF_USEROBJECTS>16
MB_ObjectInit(&MB_DEVID.User[16], MODBUS_USEROBJECT_16_NAME); MB_ObjectInit(&MB_DEVID.User[16], MODBUS_USEROBJECT_16_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_17_NAME #if defined(MODBUS_USEROBJECT_17_NAME) && MODBUS_NUMB_OF_USEROBJECTS>17
MB_ObjectInit(&MB_DEVID.User[17], MODBUS_USEROBJECT_17_NAME); MB_ObjectInit(&MB_DEVID.User[17], MODBUS_USEROBJECT_17_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_18_NAME #if defined(MODBUS_USEROBJECT_18_NAME) && MODBUS_NUMB_OF_USEROBJECTS>18
MB_ObjectInit(&MB_DEVID.User[18], MODBUS_USEROBJECT_18_NAME); MB_ObjectInit(&MB_DEVID.User[18], MODBUS_USEROBJECT_18_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_19_NAME #if defined(MODBUS_USEROBJECT_19_NAME) && MODBUS_NUMB_OF_USEROBJECTS>19
MB_ObjectInit(&MB_DEVID.User[19], MODBUS_USEROBJECT_19_NAME); MB_ObjectInit(&MB_DEVID.User[19], MODBUS_USEROBJECT_19_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_20_NAME #if defined(MODBUS_USEROBJECT_20_NAME) && MODBUS_NUMB_OF_USEROBJECTS>20
MB_ObjectInit(&MB_DEVID.User[20], MODBUS_USEROBJECT_20_NAME); MB_ObjectInit(&MB_DEVID.User[20], MODBUS_USEROBJECT_20_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_21_NAME #if defined(MODBUS_USEROBJECT_21_NAME) && MODBUS_NUMB_OF_USEROBJECTS>21
MB_ObjectInit(&MB_DEVID.User[21], MODBUS_USEROBJECT_21_NAME); MB_ObjectInit(&MB_DEVID.User[21], MODBUS_USEROBJECT_21_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_22_NAME #if defined(MODBUS_USEROBJECT_22_NAME) && MODBUS_NUMB_OF_USEROBJECTS>22
MB_ObjectInit(&MB_DEVID.User[22], MODBUS_USEROBJECT_22_NAME); MB_ObjectInit(&MB_DEVID.User[22], MODBUS_USEROBJECT_22_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_23_NAME #if defined(MODBUS_USEROBJECT_23_NAME) && MODBUS_NUMB_OF_USEROBJECTS>23
MB_ObjectInit(&MB_DEVID.User[23], MODBUS_USEROBJECT_23_NAME); MB_ObjectInit(&MB_DEVID.User[23], MODBUS_USEROBJECT_23_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_24_NAME #if defined(MODBUS_USEROBJECT_24_NAME) && MODBUS_NUMB_OF_USEROBJECTS>24
MB_ObjectInit(&MB_DEVID.User[24], MODBUS_USEROBJECT_24_NAME); MB_ObjectInit(&MB_DEVID.User[24], MODBUS_USEROBJECT_24_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_25_NAME #if defined(MODBUS_USEROBJECT_25_NAME) && MODBUS_NUMB_OF_USEROBJECTS>25
MB_ObjectInit(&MB_DEVID.User[25], MODBUS_USEROBJECT_25_NAME); MB_ObjectInit(&MB_DEVID.User[25], MODBUS_USEROBJECT_25_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_26_NAME #if defined(MODBUS_USEROBJECT_26_NAME) && MODBUS_NUMB_OF_USEROBJECTS>26
MB_ObjectInit(&MB_DEVID.User[26], MODBUS_USEROBJECT_26_NAME); MB_ObjectInit(&MB_DEVID.User[26], MODBUS_USEROBJECT_26_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_27_NAME #if defined(MODBUS_USEROBJECT_27_NAME) && MODBUS_NUMB_OF_USEROBJECTS>27
MB_ObjectInit(&MB_DEVID.User[27], MODBUS_USEROBJECT_27_NAME); MB_ObjectInit(&MB_DEVID.User[27], MODBUS_USEROBJECT_27_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_28_NAME #if defined(MODBUS_USEROBJECT_28_NAME) && MODBUS_NUMB_OF_USEROBJECTS>28
MB_ObjectInit(&MB_DEVID.User[28], MODBUS_USEROBJECT_28_NAME); MB_ObjectInit(&MB_DEVID.User[28], MODBUS_USEROBJECT_28_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_29_NAME #if defined(MODBUS_USEROBJECT_29_NAME) && MODBUS_NUMB_OF_USEROBJECTS>29
MB_ObjectInit(&MB_DEVID.User[29], MODBUS_USEROBJECT_29_NAME); MB_ObjectInit(&MB_DEVID.User[29], MODBUS_USEROBJECT_29_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_30_NAME #if defined(MODBUS_USEROBJECT_30_NAME) && MODBUS_NUMB_OF_USEROBJECTS>30
MB_ObjectInit(&MB_DEVID.User[30], MODBUS_USEROBJECT_30_NAME); MB_ObjectInit(&MB_DEVID.User[30], MODBUS_USEROBJECT_30_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_31_NAME #if defined(MODBUS_USEROBJECT_31_NAME) && MODBUS_NUMB_OF_USEROBJECTS>31
MB_ObjectInit(&MB_DEVID.User[31], MODBUS_USEROBJECT_31_NAME); MB_ObjectInit(&MB_DEVID.User[31], MODBUS_USEROBJECT_31_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_32_NAME #if defined(MODBUS_USEROBJECT_32_NAME) && MODBUS_NUMB_OF_USEROBJECTS>32
MB_ObjectInit(&MB_DEVID.User[32], MODBUS_USEROBJECT_32_NAME); MB_ObjectInit(&MB_DEVID.User[32], MODBUS_USEROBJECT_32_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_33_NAME #if defined(MODBUS_USEROBJECT_33_NAME) && MODBUS_NUMB_OF_USEROBJECTS>33
MB_ObjectInit(&MB_DEVID.User[33], MODBUS_USEROBJECT_33_NAME); MB_ObjectInit(&MB_DEVID.User[33], MODBUS_USEROBJECT_33_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_34_NAME #if defined(MODBUS_USEROBJECT_34_NAME) && MODBUS_NUMB_OF_USEROBJECTS>34
MB_ObjectInit(&MB_DEVID.User[34], MODBUS_USEROBJECT_34_NAME); MB_ObjectInit(&MB_DEVID.User[34], MODBUS_USEROBJECT_34_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_35_NAME #if defined(MODBUS_USEROBJECT_35_NAME) && MODBUS_NUMB_OF_USEROBJECTS>35
MB_ObjectInit(&MB_DEVID.User[35], MODBUS_USEROBJECT_35_NAME); MB_ObjectInit(&MB_DEVID.User[35], MODBUS_USEROBJECT_35_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_36_NAME #if defined(MODBUS_USEROBJECT_36_NAME) && MODBUS_NUMB_OF_USEROBJECTS>36
MB_ObjectInit(&MB_DEVID.User[36], MODBUS_USEROBJECT_36_NAME); MB_ObjectInit(&MB_DEVID.User[36], MODBUS_USEROBJECT_36_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_37_NAME #if defined(MODBUS_USEROBJECT_37_NAME) && MODBUS_NUMB_OF_USEROBJECTS>37
MB_ObjectInit(&MB_DEVID.User[37], MODBUS_USEROBJECT_37_NAME); MB_ObjectInit(&MB_DEVID.User[37], MODBUS_USEROBJECT_37_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_38_NAME #if defined(MODBUS_USEROBJECT_38_NAME) && MODBUS_NUMB_OF_USEROBJECTS>38
MB_ObjectInit(&MB_DEVID.User[38], MODBUS_USEROBJECT_38_NAME); MB_ObjectInit(&MB_DEVID.User[38], MODBUS_USEROBJECT_38_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_39_NAME #if defined(MODBUS_USEROBJECT_39_NAME) && MODBUS_NUMB_OF_USEROBJECTS>39
MB_ObjectInit(&MB_DEVID.User[39], MODBUS_USEROBJECT_39_NAME); MB_ObjectInit(&MB_DEVID.User[39], MODBUS_USEROBJECT_39_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_40_NAME #if defined(MODBUS_USEROBJECT_40_NAME) && MODBUS_NUMB_OF_USEROBJECTS>40
MB_ObjectInit(&MB_DEVID.User[40], MODBUS_USEROBJECT_40_NAME); MB_ObjectInit(&MB_DEVID.User[40], MODBUS_USEROBJECT_40_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_41_NAME #if defined(MODBUS_USEROBJECT_41_NAME) && MODBUS_NUMB_OF_USEROBJECTS>41
MB_ObjectInit(&MB_DEVID.User[41], MODBUS_USEROBJECT_41_NAME); MB_ObjectInit(&MB_DEVID.User[41], MODBUS_USEROBJECT_41_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_42_NAME #if defined(MODBUS_USEROBJECT_42_NAME) && MODBUS_NUMB_OF_USEROBJECTS>42
MB_ObjectInit(&MB_DEVID.User[42], MODBUS_USEROBJECT_42_NAME); MB_ObjectInit(&MB_DEVID.User[42], MODBUS_USEROBJECT_42_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_43_NAME #if defined(MODBUS_USEROBJECT_43_NAME) && MODBUS_NUMB_OF_USEROBJECTS>43
MB_ObjectInit(&MB_DEVID.User[43], MODBUS_USEROBJECT_43_NAME); MB_ObjectInit(&MB_DEVID.User[43], MODBUS_USEROBJECT_43_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_44_NAME #if defined(MODBUS_USEROBJECT_44_NAME) && MODBUS_NUMB_OF_USEROBJECTS>44
MB_ObjectInit(&MB_DEVID.User[44], MODBUS_USEROBJECT_44_NAME); MB_ObjectInit(&MB_DEVID.User[44], MODBUS_USEROBJECT_44_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_45_NAME #if defined(MODBUS_USEROBJECT_45_NAME) && MODBUS_NUMB_OF_USEROBJECTS>45
MB_ObjectInit(&MB_DEVID.User[45], MODBUS_USEROBJECT_45_NAME); MB_ObjectInit(&MB_DEVID.User[45], MODBUS_USEROBJECT_45_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_46_NAME #if defined(MODBUS_USEROBJECT_46_NAME) && MODBUS_NUMB_OF_USEROBJECTS>46
MB_ObjectInit(&MB_DEVID.User[46], MODBUS_USEROBJECT_46_NAME); MB_ObjectInit(&MB_DEVID.User[46], MODBUS_USEROBJECT_46_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_47_NAME #if defined(MODBUS_USEROBJECT_47_NAME) && MODBUS_NUMB_OF_USEROBJECTS>47
MB_ObjectInit(&MB_DEVID.User[47], MODBUS_USEROBJECT_47_NAME); MB_ObjectInit(&MB_DEVID.User[47], MODBUS_USEROBJECT_47_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_48_NAME #if defined(MODBUS_USEROBJECT_48_NAME) && MODBUS_NUMB_OF_USEROBJECTS>48
MB_ObjectInit(&MB_DEVID.User[48], MODBUS_USEROBJECT_48_NAME); MB_ObjectInit(&MB_DEVID.User[48], MODBUS_USEROBJECT_48_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_49_NAME #if defined(MODBUS_USEROBJECT_49_NAME) && MODBUS_NUMB_OF_USEROBJECTS>49
MB_ObjectInit(&MB_DEVID.User[49], MODBUS_USEROBJECT_49_NAME); MB_ObjectInit(&MB_DEVID.User[49], MODBUS_USEROBJECT_49_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_50_NAME #if defined(MODBUS_USEROBJECT_50_NAME) && MODBUS_NUMB_OF_USEROBJECTS>50
MB_ObjectInit(&MB_DEVID.User[50], MODBUS_USEROBJECT_50_NAME); MB_ObjectInit(&MB_DEVID.User[50], MODBUS_USEROBJECT_50_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_51_NAME #if defined(MODBUS_USEROBJECT_51_NAME) && MODBUS_NUMB_OF_USEROBJECTS>51
MB_ObjectInit(&MB_DEVID.User[51], MODBUS_USEROBJECT_51_NAME); MB_ObjectInit(&MB_DEVID.User[51], MODBUS_USEROBJECT_51_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_52_NAME #if defined(MODBUS_USEROBJECT_52_NAME) && MODBUS_NUMB_OF_USEROBJECTS>52
MB_ObjectInit(&MB_DEVID.User[52], MODBUS_USEROBJECT_52_NAME); MB_ObjectInit(&MB_DEVID.User[52], MODBUS_USEROBJECT_52_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_53_NAME #if defined(MODBUS_USEROBJECT_53_NAME) && MODBUS_NUMB_OF_USEROBJECTS>53
MB_ObjectInit(&MB_DEVID.User[53], MODBUS_USEROBJECT_53_NAME); MB_ObjectInit(&MB_DEVID.User[53], MODBUS_USEROBJECT_53_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_54_NAME #if defined(MODBUS_USEROBJECT_54_NAME) && MODBUS_NUMB_OF_USEROBJECTS>54
MB_ObjectInit(&MB_DEVID.User[54], MODBUS_USEROBJECT_54_NAME); MB_ObjectInit(&MB_DEVID.User[54], MODBUS_USEROBJECT_54_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_55_NAME #if defined(MODBUS_USEROBJECT_55_NAME) && MODBUS_NUMB_OF_USEROBJECTS>55
MB_ObjectInit(&MB_DEVID.User[55], MODBUS_USEROBJECT_55_NAME); MB_ObjectInit(&MB_DEVID.User[55], MODBUS_USEROBJECT_55_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_56_NAME #if defined(MODBUS_USEROBJECT_56_NAME) && MODBUS_NUMB_OF_USEROBJECTS>56
MB_ObjectInit(&MB_DEVID.User[56], MODBUS_USEROBJECT_56_NAME); MB_ObjectInit(&MB_DEVID.User[56], MODBUS_USEROBJECT_56_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_57_NAME #if defined(MODBUS_USEROBJECT_57_NAME) && MODBUS_NUMB_OF_USEROBJECTS>57
MB_ObjectInit(&MB_DEVID.User[57], MODBUS_USEROBJECT_57_NAME); MB_ObjectInit(&MB_DEVID.User[57], MODBUS_USEROBJECT_57_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_58_NAME #if defined(MODBUS_USEROBJECT_58_NAME) && MODBUS_NUMB_OF_USEROBJECTS>58
MB_ObjectInit(&MB_DEVID.User[58], MODBUS_USEROBJECT_58_NAME); MB_ObjectInit(&MB_DEVID.User[58], MODBUS_USEROBJECT_58_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_59_NAME #if defined(MODBUS_USEROBJECT_59_NAME) && MODBUS_NUMB_OF_USEROBJECTS>59
MB_ObjectInit(&MB_DEVID.User[59], MODBUS_USEROBJECT_59_NAME); MB_ObjectInit(&MB_DEVID.User[59], MODBUS_USEROBJECT_59_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_60_NAME #if defined(MODBUS_USEROBJECT_60_NAME) && MODBUS_NUMB_OF_USEROBJECTS>60
MB_ObjectInit(&MB_DEVID.User[60], MODBUS_USEROBJECT_60_NAME); MB_ObjectInit(&MB_DEVID.User[60], MODBUS_USEROBJECT_60_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_61_NAME #if defined(MODBUS_USEROBJECT_61_NAME) && MODBUS_NUMB_OF_USEROBJECTS>61
MB_ObjectInit(&MB_DEVID.User[61], MODBUS_USEROBJECT_61_NAME); MB_ObjectInit(&MB_DEVID.User[61], MODBUS_USEROBJECT_61_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_62_NAME #if defined(MODBUS_USEROBJECT_62_NAME) && MODBUS_NUMB_OF_USEROBJECTS>62
MB_ObjectInit(&MB_DEVID.User[62], MODBUS_USEROBJECT_62_NAME); MB_ObjectInit(&MB_DEVID.User[62], MODBUS_USEROBJECT_62_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_63_NAME #if defined(MODBUS_USEROBJECT_63_NAME) && MODBUS_NUMB_OF_USEROBJECTS>63
MB_ObjectInit(&MB_DEVID.User[63], MODBUS_USEROBJECT_63_NAME); MB_ObjectInit(&MB_DEVID.User[63], MODBUS_USEROBJECT_63_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_64_NAME #if defined(MODBUS_USEROBJECT_64_NAME) && MODBUS_NUMB_OF_USEROBJECTS>64
MB_ObjectInit(&MB_DEVID.User[64], MODBUS_USEROBJECT_64_NAME); MB_ObjectInit(&MB_DEVID.User[64], MODBUS_USEROBJECT_64_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_65_NAME #if defined(MODBUS_USEROBJECT_65_NAME) && MODBUS_NUMB_OF_USEROBJECTS>65
MB_ObjectInit(&MB_DEVID.User[65], MODBUS_USEROBJECT_65_NAME); MB_ObjectInit(&MB_DEVID.User[65], MODBUS_USEROBJECT_65_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_66_NAME #if defined(MODBUS_USEROBJECT_66_NAME) && MODBUS_NUMB_OF_USEROBJECTS>66
MB_ObjectInit(&MB_DEVID.User[66], MODBUS_USEROBJECT_66_NAME); MB_ObjectInit(&MB_DEVID.User[66], MODBUS_USEROBJECT_66_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_67_NAME #if defined(MODBUS_USEROBJECT_67_NAME) && MODBUS_NUMB_OF_USEROBJECTS>67
MB_ObjectInit(&MB_DEVID.User[67], MODBUS_USEROBJECT_67_NAME); MB_ObjectInit(&MB_DEVID.User[67], MODBUS_USEROBJECT_67_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_68_NAME #if defined(MODBUS_USEROBJECT_68_NAME) && MODBUS_NUMB_OF_USEROBJECTS>68
MB_ObjectInit(&MB_DEVID.User[68], MODBUS_USEROBJECT_68_NAME); MB_ObjectInit(&MB_DEVID.User[68], MODBUS_USEROBJECT_68_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_69_NAME #if defined(MODBUS_USEROBJECT_69_NAME) && MODBUS_NUMB_OF_USEROBJECTS>69
MB_ObjectInit(&MB_DEVID.User[69], MODBUS_USEROBJECT_69_NAME); MB_ObjectInit(&MB_DEVID.User[69], MODBUS_USEROBJECT_69_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_70_NAME #if defined(MODBUS_USEROBJECT_70_NAME) && MODBUS_NUMB_OF_USEROBJECTS>70
MB_ObjectInit(&MB_DEVID.User[70], MODBUS_USEROBJECT_70_NAME); MB_ObjectInit(&MB_DEVID.User[70], MODBUS_USEROBJECT_70_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_71_NAME #if defined(MODBUS_USEROBJECT_71_NAME) && MODBUS_NUMB_OF_USEROBJECTS>71
MB_ObjectInit(&MB_DEVID.User[71], MODBUS_USEROBJECT_71_NAME); MB_ObjectInit(&MB_DEVID.User[71], MODBUS_USEROBJECT_71_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_72_NAME #if defined(MODBUS_USEROBJECT_72_NAME) && MODBUS_NUMB_OF_USEROBJECTS>72
MB_ObjectInit(&MB_DEVID.User[72], MODBUS_USEROBJECT_72_NAME); MB_ObjectInit(&MB_DEVID.User[72], MODBUS_USEROBJECT_72_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_73_NAME #if defined(MODBUS_USEROBJECT_73_NAME) && MODBUS_NUMB_OF_USEROBJECTS>73
MB_ObjectInit(&MB_DEVID.User[73], MODBUS_USEROBJECT_73_NAME); MB_ObjectInit(&MB_DEVID.User[73], MODBUS_USEROBJECT_73_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_74_NAME #if defined(MODBUS_USEROBJECT_74_NAME) && MODBUS_NUMB_OF_USEROBJECTS>74
MB_ObjectInit(&MB_DEVID.User[74], MODBUS_USEROBJECT_74_NAME); MB_ObjectInit(&MB_DEVID.User[74], MODBUS_USEROBJECT_74_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_75_NAME #if defined(MODBUS_USEROBJECT_75_NAME) && MODBUS_NUMB_OF_USEROBJECTS>75
MB_ObjectInit(&MB_DEVID.User[75], MODBUS_USEROBJECT_75_NAME); MB_ObjectInit(&MB_DEVID.User[75], MODBUS_USEROBJECT_75_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_76_NAME #if defined(MODBUS_USEROBJECT_76_NAME) && MODBUS_NUMB_OF_USEROBJECTS>76
MB_ObjectInit(&MB_DEVID.User[76], MODBUS_USEROBJECT_76_NAME); MB_ObjectInit(&MB_DEVID.User[76], MODBUS_USEROBJECT_76_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_77_NAME #if defined(MODBUS_USEROBJECT_77_NAME) && MODBUS_NUMB_OF_USEROBJECTS>77
MB_ObjectInit(&MB_DEVID.User[77], MODBUS_USEROBJECT_77_NAME); MB_ObjectInit(&MB_DEVID.User[77], MODBUS_USEROBJECT_77_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_78_NAME #if defined(MODBUS_USEROBJECT_78_NAME) && MODBUS_NUMB_OF_USEROBJECTS>78
MB_ObjectInit(&MB_DEVID.User[78], MODBUS_USEROBJECT_78_NAME); MB_ObjectInit(&MB_DEVID.User[78], MODBUS_USEROBJECT_78_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_79_NAME #if defined(MODBUS_USEROBJECT_79_NAME) && MODBUS_NUMB_OF_USEROBJECTS>79
MB_ObjectInit(&MB_DEVID.User[79], MODBUS_USEROBJECT_79_NAME); MB_ObjectInit(&MB_DEVID.User[79], MODBUS_USEROBJECT_79_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_80_NAME #if defined(MODBUS_USEROBJECT_80_NAME) && MODBUS_NUMB_OF_USEROBJECTS>80
MB_ObjectInit(&MB_DEVID.User[80], MODBUS_USEROBJECT_80_NAME); MB_ObjectInit(&MB_DEVID.User[80], MODBUS_USEROBJECT_80_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_81_NAME #if defined(MODBUS_USEROBJECT_81_NAME) && MODBUS_NUMB_OF_USEROBJECTS>81
MB_ObjectInit(&MB_DEVID.User[81], MODBUS_USEROBJECT_81_NAME); MB_ObjectInit(&MB_DEVID.User[81], MODBUS_USEROBJECT_81_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_82_NAME #if defined(MODBUS_USEROBJECT_82_NAME) && MODBUS_NUMB_OF_USEROBJECTS>82
MB_ObjectInit(&MB_DEVID.User[82], MODBUS_USEROBJECT_82_NAME); MB_ObjectInit(&MB_DEVID.User[82], MODBUS_USEROBJECT_82_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_83_NAME #if defined(MODBUS_USEROBJECT_83_NAME) && MODBUS_NUMB_OF_USEROBJECTS>83
MB_ObjectInit(&MB_DEVID.User[83], MODBUS_USEROBJECT_83_NAME); MB_ObjectInit(&MB_DEVID.User[83], MODBUS_USEROBJECT_83_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_84_NAME #if defined(MODBUS_USEROBJECT_84_NAME) && MODBUS_NUMB_OF_USEROBJECTS>84
MB_ObjectInit(&MB_DEVID.User[84], MODBUS_USEROBJECT_84_NAME); MB_ObjectInit(&MB_DEVID.User[84], MODBUS_USEROBJECT_84_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_85_NAME #if defined(MODBUS_USEROBJECT_85_NAME) && MODBUS_NUMB_OF_USEROBJECTS>85
MB_ObjectInit(&MB_DEVID.User[85], MODBUS_USEROBJECT_85_NAME); MB_ObjectInit(&MB_DEVID.User[85], MODBUS_USEROBJECT_85_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_86_NAME #if defined(MODBUS_USEROBJECT_86_NAME) && MODBUS_NUMB_OF_USEROBJECTS>86
MB_ObjectInit(&MB_DEVID.User[86], MODBUS_USEROBJECT_86_NAME); MB_ObjectInit(&MB_DEVID.User[86], MODBUS_USEROBJECT_86_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_87_NAME #if defined(MODBUS_USEROBJECT_87_NAME) && MODBUS_NUMB_OF_USEROBJECTS>87
MB_ObjectInit(&MB_DEVID.User[87], MODBUS_USEROBJECT_87_NAME); MB_ObjectInit(&MB_DEVID.User[87], MODBUS_USEROBJECT_87_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_88_NAME #if defined(MODBUS_USEROBJECT_88_NAME) && MODBUS_NUMB_OF_USEROBJECTS>88
MB_ObjectInit(&MB_DEVID.User[88], MODBUS_USEROBJECT_88_NAME); MB_ObjectInit(&MB_DEVID.User[88], MODBUS_USEROBJECT_88_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_89_NAME #if defined(MODBUS_USEROBJECT_89_NAME) && MODBUS_NUMB_OF_USEROBJECTS>89
MB_ObjectInit(&MB_DEVID.User[89], MODBUS_USEROBJECT_89_NAME); MB_ObjectInit(&MB_DEVID.User[89], MODBUS_USEROBJECT_89_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_90_NAME #if defined(MODBUS_USEROBJECT_90_NAME) && MODBUS_NUMB_OF_USEROBJECTS>90
MB_ObjectInit(&MB_DEVID.User[90], MODBUS_USEROBJECT_90_NAME); MB_ObjectInit(&MB_DEVID.User[90], MODBUS_USEROBJECT_90_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_91_NAME #if defined(MODBUS_USEROBJECT_91_NAME) && MODBUS_NUMB_OF_USEROBJECTS>91
MB_ObjectInit(&MB_DEVID.User[91], MODBUS_USEROBJECT_91_NAME); MB_ObjectInit(&MB_DEVID.User[91], MODBUS_USEROBJECT_91_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_92_NAME #if defined(MODBUS_USEROBJECT_92_NAME) && MODBUS_NUMB_OF_USEROBJECTS>92
MB_ObjectInit(&MB_DEVID.User[92], MODBUS_USEROBJECT_92_NAME); MB_ObjectInit(&MB_DEVID.User[92], MODBUS_USEROBJECT_92_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_93_NAME #if defined(MODBUS_USEROBJECT_93_NAME) && MODBUS_NUMB_OF_USEROBJECTS>93
MB_ObjectInit(&MB_DEVID.User[93], MODBUS_USEROBJECT_93_NAME); MB_ObjectInit(&MB_DEVID.User[93], MODBUS_USEROBJECT_93_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_94_NAME #if defined(MODBUS_USEROBJECT_94_NAME) && MODBUS_NUMB_OF_USEROBJECTS>94
MB_ObjectInit(&MB_DEVID.User[94], MODBUS_USEROBJECT_94_NAME); MB_ObjectInit(&MB_DEVID.User[94], MODBUS_USEROBJECT_94_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_95_NAME #if defined(MODBUS_USEROBJECT_95_NAME) && MODBUS_NUMB_OF_USEROBJECTS>95
MB_ObjectInit(&MB_DEVID.User[95], MODBUS_USEROBJECT_95_NAME); MB_ObjectInit(&MB_DEVID.User[95], MODBUS_USEROBJECT_95_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_96_NAME #if defined(MODBUS_USEROBJECT_96_NAME) && MODBUS_NUMB_OF_USEROBJECTS>96
MB_ObjectInit(&MB_DEVID.User[96], MODBUS_USEROBJECT_96_NAME); MB_ObjectInit(&MB_DEVID.User[96], MODBUS_USEROBJECT_96_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_97_NAME #if defined(MODBUS_USEROBJECT_97_NAME) && MODBUS_NUMB_OF_USEROBJECTS>97
MB_ObjectInit(&MB_DEVID.User[97], MODBUS_USEROBJECT_97_NAME); MB_ObjectInit(&MB_DEVID.User[97], MODBUS_USEROBJECT_97_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_98_NAME #if defined(MODBUS_USEROBJECT_98_NAME) && MODBUS_NUMB_OF_USEROBJECTS>98
MB_ObjectInit(&MB_DEVID.User[98], MODBUS_USEROBJECT_98_NAME); MB_ObjectInit(&MB_DEVID.User[98], MODBUS_USEROBJECT_98_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_99_NAME #if defined(MODBUS_USEROBJECT_99_NAME) && MODBUS_NUMB_OF_USEROBJECTS>99
MB_ObjectInit(&MB_DEVID.User[99], MODBUS_USEROBJECT_99_NAME); MB_ObjectInit(&MB_DEVID.User[99], MODBUS_USEROBJECT_99_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_100_NAME #if defined(MODBUS_USEROBJECT_100_NAME) && MODBUS_NUMB_OF_USEROBJECTS>100
MB_ObjectInit(&MB_DEVID.User[100], MODBUS_USEROBJECT_100_NAME); MB_ObjectInit(&MB_DEVID.User[100], MODBUS_USEROBJECT_100_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_101_NAME #if defined(MODBUS_USEROBJECT_101_NAME) && MODBUS_NUMB_OF_USEROBJECTS>101
MB_ObjectInit(&MB_DEVID.User[101], MODBUS_USEROBJECT_101_NAME); MB_ObjectInit(&MB_DEVID.User[101], MODBUS_USEROBJECT_101_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_102_NAME #if defined(MODBUS_USEROBJECT_102_NAME) && MODBUS_NUMB_OF_USEROBJECTS>102
MB_ObjectInit(&MB_DEVID.User[102], MODBUS_USEROBJECT_102_NAME); MB_ObjectInit(&MB_DEVID.User[102], MODBUS_USEROBJECT_102_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_103_NAME #if defined(MODBUS_USEROBJECT_103_NAME) && MODBUS_NUMB_OF_USEROBJECTS>103
MB_ObjectInit(&MB_DEVID.User[103], MODBUS_USEROBJECT_103_NAME); MB_ObjectInit(&MB_DEVID.User[103], MODBUS_USEROBJECT_103_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_104_NAME #if defined(MODBUS_USEROBJECT_104_NAME) && MODBUS_NUMB_OF_USEROBJECTS>104
MB_ObjectInit(&MB_DEVID.User[104], MODBUS_USEROBJECT_104_NAME); MB_ObjectInit(&MB_DEVID.User[104], MODBUS_USEROBJECT_104_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_105_NAME #if defined(MODBUS_USEROBJECT_105_NAME) && MODBUS_NUMB_OF_USEROBJECTS>105
MB_ObjectInit(&MB_DEVID.User[105], MODBUS_USEROBJECT_105_NAME); MB_ObjectInit(&MB_DEVID.User[105], MODBUS_USEROBJECT_105_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_106_NAME #if defined(MODBUS_USEROBJECT_106_NAME) && MODBUS_NUMB_OF_USEROBJECTS>106
MB_ObjectInit(&MB_DEVID.User[106], MODBUS_USEROBJECT_106_NAME); MB_ObjectInit(&MB_DEVID.User[106], MODBUS_USEROBJECT_106_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_107_NAME #if defined(MODBUS_USEROBJECT_107_NAME) && MODBUS_NUMB_OF_USEROBJECTS>107
MB_ObjectInit(&MB_DEVID.User[107], MODBUS_USEROBJECT_107_NAME); MB_ObjectInit(&MB_DEVID.User[107], MODBUS_USEROBJECT_107_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_108_NAME #if defined(MODBUS_USEROBJECT_108_NAME) && MODBUS_NUMB_OF_USEROBJECTS>108
MB_ObjectInit(&MB_DEVID.User[108], MODBUS_USEROBJECT_108_NAME); MB_ObjectInit(&MB_DEVID.User[108], MODBUS_USEROBJECT_108_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_109_NAME #if defined(MODBUS_USEROBJECT_109_NAME) && MODBUS_NUMB_OF_USEROBJECTS>109
MB_ObjectInit(&MB_DEVID.User[109], MODBUS_USEROBJECT_109_NAME); MB_ObjectInit(&MB_DEVID.User[109], MODBUS_USEROBJECT_109_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_110_NAME #if defined(MODBUS_USEROBJECT_110_NAME) && MODBUS_NUMB_OF_USEROBJECTS>110
MB_ObjectInit(&MB_DEVID.User[110], MODBUS_USEROBJECT_110_NAME); MB_ObjectInit(&MB_DEVID.User[110], MODBUS_USEROBJECT_110_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_111_NAME #if defined(MODBUS_USEROBJECT_111_NAME) && MODBUS_NUMB_OF_USEROBJECTS>111
MB_ObjectInit(&MB_DEVID.User[111], MODBUS_USEROBJECT_111_NAME); MB_ObjectInit(&MB_DEVID.User[111], MODBUS_USEROBJECT_111_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_112_NAME #if defined(MODBUS_USEROBJECT_112_NAME) && MODBUS_NUMB_OF_USEROBJECTS>112
MB_ObjectInit(&MB_DEVID.User[112], MODBUS_USEROBJECT_112_NAME); MB_ObjectInit(&MB_DEVID.User[112], MODBUS_USEROBJECT_112_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_113_NAME #if defined(MODBUS_USEROBJECT_113_NAME) && MODBUS_NUMB_OF_USEROBJECTS>113
MB_ObjectInit(&MB_DEVID.User[113], MODBUS_USEROBJECT_113_NAME); MB_ObjectInit(&MB_DEVID.User[113], MODBUS_USEROBJECT_113_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_114_NAME #if defined(MODBUS_USEROBJECT_114_NAME) && MODBUS_NUMB_OF_USEROBJECTS>114
MB_ObjectInit(&MB_DEVID.User[114], MODBUS_USEROBJECT_114_NAME); MB_ObjectInit(&MB_DEVID.User[114], MODBUS_USEROBJECT_114_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_115_NAME #if defined(MODBUS_USEROBJECT_115_NAME) && MODBUS_NUMB_OF_USEROBJECTS>115
MB_ObjectInit(&MB_DEVID.User[115], MODBUS_USEROBJECT_115_NAME); MB_ObjectInit(&MB_DEVID.User[115], MODBUS_USEROBJECT_115_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_116_NAME #if defined(MODBUS_USEROBJECT_116_NAME) && MODBUS_NUMB_OF_USEROBJECTS>116
MB_ObjectInit(&MB_DEVID.User[116], MODBUS_USEROBJECT_116_NAME); MB_ObjectInit(&MB_DEVID.User[116], MODBUS_USEROBJECT_116_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_117_NAME #if defined(MODBUS_USEROBJECT_117_NAME) && MODBUS_NUMB_OF_USEROBJECTS>117
MB_ObjectInit(&MB_DEVID.User[117], MODBUS_USEROBJECT_117_NAME); MB_ObjectInit(&MB_DEVID.User[117], MODBUS_USEROBJECT_117_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_118_NAME #if defined(MODBUS_USEROBJECT_118_NAME) && MODBUS_NUMB_OF_USEROBJECTS>118
MB_ObjectInit(&MB_DEVID.User[118], MODBUS_USEROBJECT_118_NAME); MB_ObjectInit(&MB_DEVID.User[118], MODBUS_USEROBJECT_118_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_119_NAME #if defined(MODBUS_USEROBJECT_119_NAME) && MODBUS_NUMB_OF_USEROBJECTS>119
MB_ObjectInit(&MB_DEVID.User[119], MODBUS_USEROBJECT_119_NAME); MB_ObjectInit(&MB_DEVID.User[119], MODBUS_USEROBJECT_119_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_120_NAME #if defined(MODBUS_USEROBJECT_120_NAME) && MODBUS_NUMB_OF_USEROBJECTS>120
MB_ObjectInit(&MB_DEVID.User[120], MODBUS_USEROBJECT_120_NAME); MB_ObjectInit(&MB_DEVID.User[120], MODBUS_USEROBJECT_120_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_121_NAME #if defined(MODBUS_USEROBJECT_121_NAME) && MODBUS_NUMB_OF_USEROBJECTS>121
MB_ObjectInit(&MB_DEVID.User[121], MODBUS_USEROBJECT_121_NAME); MB_ObjectInit(&MB_DEVID.User[121], MODBUS_USEROBJECT_121_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_122_NAME #if defined(MODBUS_USEROBJECT_122_NAME) && MODBUS_NUMB_OF_USEROBJECTS>122
MB_ObjectInit(&MB_DEVID.User[122], MODBUS_USEROBJECT_122_NAME); MB_ObjectInit(&MB_DEVID.User[122], MODBUS_USEROBJECT_122_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_123_NAME #if defined(MODBUS_USEROBJECT_123_NAME) && MODBUS_NUMB_OF_USEROBJECTS>123
MB_ObjectInit(&MB_DEVID.User[123], MODBUS_USEROBJECT_123_NAME); MB_ObjectInit(&MB_DEVID.User[123], MODBUS_USEROBJECT_123_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_124_NAME #if defined(MODBUS_USEROBJECT_124_NAME) && MODBUS_NUMB_OF_USEROBJECTS>124
MB_ObjectInit(&MB_DEVID.User[124], MODBUS_USEROBJECT_124_NAME); MB_ObjectInit(&MB_DEVID.User[124], MODBUS_USEROBJECT_124_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_125_NAME #if defined(MODBUS_USEROBJECT_125_NAME) && MODBUS_NUMB_OF_USEROBJECTS>125
MB_ObjectInit(&MB_DEVID.User[125], MODBUS_USEROBJECT_125_NAME); MB_ObjectInit(&MB_DEVID.User[125], MODBUS_USEROBJECT_125_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_126_NAME #if defined(MODBUS_USEROBJECT_126_NAME) && MODBUS_NUMB_OF_USEROBJECTS>126
MB_ObjectInit(&MB_DEVID.User[126], MODBUS_USEROBJECT_126_NAME); MB_ObjectInit(&MB_DEVID.User[126], MODBUS_USEROBJECT_126_NAME);
#endif #endif
#ifdef MODBUS_USEROBJECT_127_NAME #if defined(MODBUS_USEROBJECT_127_NAME) && MODBUS_NUMB_OF_USEROBJECTS>127
MB_ObjectInit(&MB_DEVID.User[127], MODBUS_USEROBJECT_127_NAME); MB_ObjectInit(&MB_DEVID.User[127], MODBUS_USEROBJECT_127_NAME);
#endif #endif
} }
#endif //MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
#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

View File

@@ -1,8 +1,8 @@
/** /**
****************************************************************************** *******************************************************************************
* @file modbus_diag.c * @file modbus_diag.c
* @brief Реализация диагностики устройства Modbus * @brief Реализация диагностики устройства Modbus
****************************************************************************** *******************************************************************************
* @details * @details
Модуль обработки запросов диагностической информации (0x08): Модуль обработки запросов диагностической информации (0x08):
- Полная поддержка всех подфункций диагностики согласно спецификации Modbus - Полная поддержка всех подфункций диагностики согласно спецификации Modbus
@@ -36,29 +36,6 @@ void MB_DiagnosticsInit(void)
} }
/**
* @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 Выставить бит в регистре диагностике * @brief Выставить бит в регистре диагностике
* @param bit_num Номер бита для выставления (1-15, 0 бит нельзя выставить) * @param bit_num Номер бита для выставления (1-15, 0 бит нельзя выставить)
@@ -97,8 +74,8 @@ int MB_Diagnostics_GetBit(int bit_num)
*/ */
uint8_t MB_Process_Diagnostics(RS_MsgTypeDef *modbus_msg) uint8_t MB_Process_Diagnostics(RS_MsgTypeDef *modbus_msg)
{ {
uint16_t sub_function = modbus_msg->DATA[0]; uint16_t sub_function = modbus_msg->MbData[0];
uint16_t request_data = modbus_msg->DATA[1]; uint16_t request_data = modbus_msg->MbData[1];
// Если устройство в режиме Listen Only, отвечаем только на sub-function 0x01 // Если устройство в режиме Listen Only, отвечаем только на sub-function 0x01
if (MB_DIAG.DeviceMode == MODBUS_LISTEN_ONLY_MODE && sub_function != 0x0001) if (MB_DIAG.DeviceMode == MODBUS_LISTEN_ONLY_MODE && sub_function != 0x0001)
@@ -110,8 +87,8 @@ uint8_t MB_Process_Diagnostics(RS_MsgTypeDef *modbus_msg)
{ {
case 0x0000: // Return Query Data case 0x0000: // Return Query Data
// Эхо-ответ с теми же данными // Эхо-ответ с теми же данными
modbus_msg->DATA[0] = sub_function; modbus_msg->MbData[0] = sub_function;
modbus_msg->DATA[1] = request_data; modbus_msg->MbData[1] = request_data;
modbus_msg->ByteCnt = 4; modbus_msg->ByteCnt = 4;
break; break;
@@ -137,21 +114,21 @@ uint8_t MB_Process_Diagnostics(RS_MsgTypeDef *modbus_msg)
MB_DIAG.Counters.BusCharacterOverrun = 0; MB_DIAG.Counters.BusCharacterOverrun = 0;
} }
modbus_msg->DATA[0] = sub_function; modbus_msg->MbData[0] = sub_function;
modbus_msg->DATA[1] = request_data; modbus_msg->MbData[1] = request_data;
modbus_msg->ByteCnt = 4; modbus_msg->ByteCnt = 4;
break; break;
case 0x0002: // Return Diagnostic Register case 0x0002: // Return Diagnostic Register
modbus_msg->DATA[0] = sub_function; modbus_msg->MbData[0] = sub_function;
modbus_msg->DATA[1] = MB_DIAG.DiagnosticRegister; modbus_msg->MbData[1] = MB_DIAG.DiagnosticRegister;
modbus_msg->ByteCnt = 4; modbus_msg->ByteCnt = 4;
break; break;
case 0x0003: // Change ASCII Input Delimiter case 0x0003: // Change ASCII Input Delimiter
// В RTU режиме не поддерживается // В RTU режиме не поддерживается
modbus_msg->Func_Code |= ERR_VALUES_START; modbus_msg->FuncCode |= FC_ERR_VALUES_START;
modbus_msg->Except_Code = ILLEGAL_FUNCTION; modbus_msg->Except_Code = ET_ILLEGAL_FUNCTION;
return 0; return 0;
case 0x0004: // Force Listen Only Mode case 0x0004: // Force Listen Only Mode
@@ -161,56 +138,56 @@ uint8_t MB_Process_Diagnostics(RS_MsgTypeDef *modbus_msg)
case 0x000A: // Clear Counters and Diagnostic Register case 0x000A: // Clear Counters and Diagnostic Register
MB_DiagnosticsInit(); // Полный сброс MB_DiagnosticsInit(); // Полный сброс
modbus_msg->DATA[0] = sub_function; modbus_msg->MbData[0] = sub_function;
modbus_msg->DATA[1] = 0; modbus_msg->MbData[1] = 0;
modbus_msg->ByteCnt = 4; modbus_msg->ByteCnt = 4;
break; break;
case 0x000B: // Return Bus Message Count case 0x000B: // Return Bus Message Count
modbus_msg->DATA[0] = sub_function; modbus_msg->MbData[0] = sub_function;
modbus_msg->DATA[1] = MB_DIAG.Counters.BusMessage; modbus_msg->MbData[1] = MB_DIAG.Counters.BusMessage;
modbus_msg->ByteCnt = 4; modbus_msg->ByteCnt = 4;
break; break;
case 0x000C: // Return Bus Communication Error Count case 0x000C: // Return Bus Communication Error Count
modbus_msg->DATA[0] = sub_function; modbus_msg->MbData[0] = sub_function;
modbus_msg->DATA[1] = MB_DIAG.Counters.BusCommunicationErr; modbus_msg->MbData[1] = MB_DIAG.Counters.BusCommunicationErr;
modbus_msg->ByteCnt = 4; modbus_msg->ByteCnt = 4;
break; break;
case 0x000D: // Return Bus Exception Error Count case 0x000D: // Return Bus Exception Error Count
modbus_msg->DATA[0] = sub_function; modbus_msg->MbData[0] = sub_function;
modbus_msg->DATA[1] = MB_DIAG.Counters.BusExceptionErr; modbus_msg->MbData[1] = MB_DIAG.Counters.BusExceptionErr;
modbus_msg->ByteCnt = 4; modbus_msg->ByteCnt = 4;
break; break;
case 0x000E: // Return Server Message Count case 0x000E: // Return Server Message Count
modbus_msg->DATA[0] = sub_function; modbus_msg->MbData[0] = sub_function;
modbus_msg->DATA[1] = MB_DIAG.Counters.SlaveMessage; modbus_msg->MbData[1] = MB_DIAG.Counters.SlaveMessage;
modbus_msg->ByteCnt = 4; modbus_msg->ByteCnt = 4;
break; break;
case 0x000F: // Return Slave No Response Count case 0x000F: // Return Slave No Response Count
modbus_msg->DATA[0] = sub_function; modbus_msg->MbData[0] = sub_function;
modbus_msg->DATA[1] = MB_DIAG.Counters.SlaveNoResponse; modbus_msg->MbData[1] = MB_DIAG.Counters.SlaveNoResponse;
modbus_msg->ByteCnt = 4; modbus_msg->ByteCnt = 4;
break; break;
case 0x0010: // Return Slave NAK Count case 0x0010: // Return Slave NAK Count
modbus_msg->DATA[0] = sub_function; modbus_msg->MbData[0] = sub_function;
modbus_msg->DATA[1] = MB_DIAG.Counters.SlaveNAK; modbus_msg->MbData[1] = MB_DIAG.Counters.SlaveNAK;
modbus_msg->ByteCnt = 4; modbus_msg->ByteCnt = 4;
break; break;
case 0x0011: // Return Slave Busy Count case 0x0011: // Return Slave Busy Count
modbus_msg->DATA[0] = sub_function; modbus_msg->MbData[0] = sub_function;
modbus_msg->DATA[1] = MB_DIAG.Counters.SlaveBusy; modbus_msg->MbData[1] = MB_DIAG.Counters.SlaveBusy;
modbus_msg->ByteCnt = 4; modbus_msg->ByteCnt = 4;
break; break;
case 0x0012: // Return Bus Character Overrun Count case 0x0012: // Return Bus Character Overrun Count
modbus_msg->DATA[0] = sub_function; modbus_msg->MbData[0] = sub_function;
modbus_msg->DATA[1] = MB_DIAG.Counters.BusCharacterOverrun; modbus_msg->MbData[1] = MB_DIAG.Counters.BusCharacterOverrun;
modbus_msg->ByteCnt = 4; modbus_msg->ByteCnt = 4;
break; break;
@@ -218,14 +195,14 @@ uint8_t MB_Process_Diagnostics(RS_MsgTypeDef *modbus_msg)
MB_DIAG.Counters.BusCharacterOverrun = 0; MB_DIAG.Counters.BusCharacterOverrun = 0;
// Сбрасываем флаг переполнения в DiagnosticRegister // Сбрасываем флаг переполнения в DiagnosticRegister
MB_DIAG.DiagnosticRegister &= ~(1<<0); MB_DIAG.DiagnosticRegister &= ~(1<<0);
modbus_msg->DATA[0] = sub_function; modbus_msg->MbData[0] = sub_function;
modbus_msg->DATA[1] = 0; modbus_msg->MbData[1] = 0;
modbus_msg->ByteCnt = 4; modbus_msg->ByteCnt = 4;
break; break;
default: default:
modbus_msg->Func_Code |= ERR_VALUES_START; modbus_msg->FuncCode |= FC_ERR_VALUES_START;
modbus_msg->Except_Code = ILLEGAL_FUNCTION; modbus_msg->Except_Code = ET_ILLEGAL_FUNCTION;
return 0; return 0;
} }
@@ -316,21 +293,4 @@ MB_DeviceModeTypeDef MB_GetDeviceMode(void)
return MB_DIAG.DeviceMode; return MB_DIAG.DeviceMode;
} }
#else //MODBUS_ENABLE_DIAGNOSTICS #endif //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

View File

@@ -1,22 +1,21 @@
/** /**
****************************************************************************** *******************************************************************************
* @file modbus_holdregs.c * @file modbus_holdregs.c
* @brief Реализация работы с регистрами хранения Modbus * @brief Реализация работы с регистрами хранения Modbus
****************************************************************************** *******************************************************************************
* @details * @details
Модуль для доступа к регистрам внутри программы:
- Функции для доступа к регистрам хранения по глобальным адресам
Модуль обработки команд для holding registers (регистров хранения): Модуль обработки команд для holding registers (регистров хранения):
- Чтение множественных регистров (0x03) - копирование данных в буфер ответа - Чтение множественных регистров (0x03) - копирование данных в буфер ответа
- Запись одиночного регистра (0x06) - прямая запись значения - Запись одиночного регистра (0x06) - прямая запись значения
- Запись множественных регистров (0x10) - пакетная запись из буфера - Запись множественных регистров (0x10) - пакетная запись из буфера
@section Валидация данных: @section hvalid Валидация данных:
- Проверка соответствия количества байт и регистров - Проверка соответствия количества байт и регистров
Валидация адресов через MB_DefineRegistersAddress() - Валидация адресов через MB_DefineRegistersAddress()
- Обработка исключений при некорректных запросах - Обработка исключений при некорректных запросах
@section Echo-ответы:
При успешной записи формируется echo-ответ с теми же данными,
что были в запросе (для функций 0x05, 0x06, 0x0F, 0x10).
******************************************************************************/ ******************************************************************************/
#include "modbus_inputregs.h" #include "modbus_inputregs.h"
@@ -24,6 +23,66 @@
#ifdef MODBUS_ENABLE_HOLDINGS #ifdef MODBUS_ENABLE_HOLDINGS
/**
* @brief Записать регистр хранения по глобальному адресу.
* @param Addr Адрес регистра.
* @param WriteVal Число для записи.
* @return ExceptionCode Код исключения если регистра по адресу не существует, и ET_NO_ERRORS если все ок.
*
* @details Позволяет обратиться к любому регистру по его глобальному адрессу.
Вне зависимости от того как регистры размещены в памяти.
*/
MB_ExceptionTypeDef MB_Holding_Write_Global(uint16_t Addr, uint16_t WriteVal)
{
//---------CHECK FOR ERRORS----------
MB_ExceptionTypeDef Exception = ET_NO_ERRORS;
uint16_t *pHoldRegs;
//------------WRITE COIL-------------
Exception = MB_DefineRegistersAddress(&pHoldRegs, Addr, 1, RegisterType_Holding, 1);
if(Exception == ET_NO_ERRORS)
{
*(pHoldRegs) = WriteVal;
}
return Exception;
}
/**
* @brief Считать регистр хранения по глобальному адресу.
* @param Addr Адрес регистра.
* @param Exception Указатель на переменную для кода исключения, в случае неудачи при чтении.
* @return uint16_t Возвращает значение регистра.
*
* @details Позволяет обратиться к любому регистру по его глобальному адрессу.
Вне зависимости от того как регистры размещены в памяти.
*/
uint16_t MB_Holding_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception)
{
//---------CHECK FOR ERRORS----------
MB_ExceptionTypeDef Exception_tmp = 0;
uint16_t *pHoldRegs;
//------------READ COIL--------------
Exception_tmp = MB_DefineRegistersAddress(&pHoldRegs, Addr, 1, RegisterType_Holding, 0);
if(Exception) // if exception is not given to func fill it
*Exception = Exception_tmp;
if(Exception_tmp == ET_NO_ERRORS)
{
return *(pHoldRegs);
}
else
{
return 0;
}
}
/** /**
* @brief Обработать функцию Read Holding Registers (03 - 0x03). * @brief Обработать функцию Read Holding Registers (03 - 0x03).
* @param modbus_msg Указатель на структуру собщения modbus. * @param modbus_msg Указатель на структуру собщения modbus.
@@ -35,8 +94,8 @@ 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
uint16_t *pHoldRegs; uint16_t *pHoldRegs;
modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding); // определение адреса регистров modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding, 0); // определение адреса регистров
if(modbus_msg->Except_Code != NO_ERRORS) if(modbus_msg->Except_Code != ET_NO_ERRORS)
return 0; return 0;
@@ -47,7 +106,7 @@ uint8_t MB_Process_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg)
int i; int i;
for (i = 0; i<modbus_msg->Qnt; i++) for (i = 0; i<modbus_msg->Qnt; i++)
{ {
modbus_msg->DATA[i] = *(pHoldRegs++); modbus_msg->MbData[i] = *(pHoldRegs++);
} }
return 1; return 1;
} }
@@ -62,8 +121,8 @@ 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;
modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, 1, RegisterType_Holding); // определение адреса регистров modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, 1, RegisterType_Holding, 1); // определение адреса регистров
if(modbus_msg->Except_Code != NO_ERRORS) if(modbus_msg->Except_Code != ET_NO_ERRORS)
return 0; return 0;
//-----------WRITTING REG------------ //-----------WRITTING REG------------
@@ -87,23 +146,16 @@ uint8_t MB_Process_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg)
} }
// get origin address for data // get origin address for data
uint16_t *pHoldRegs; uint16_t *pHoldRegs;
modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding); // определение адреса регистров modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding, 1); // определение адреса регистров
if(modbus_msg->Except_Code != NO_ERRORS) if(modbus_msg->Except_Code != ET_NO_ERRORS)
return 0; return 0;
//-----------WRITTING REGS----------- //-----------WRITTING REGS-----------
for (int i = 0; i<modbus_msg->Qnt; i++) for (int i = 0; i<modbus_msg->Qnt; i++)
{ {
*(pHoldRegs++) = modbus_msg->DATA[i]; *(pHoldRegs++) = modbus_msg->MbData[i];
} }
return 1; return 1;
} }
#endif //MODBUS_ENABLE_HOLDINGS
#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

View File

@@ -1,19 +1,83 @@
/** /**
****************************************************************************** *******************************************************************************
* @file modbus_inputregs.c * @file modbus_inputregs.c
* @brief Реализация работы с входными регистрами Modbus * @brief Реализация работы с входными регистрами Modbus
****************************************************************************** *******************************************************************************
* @details * @details
Модуль для доступа к регистрам внутри программы:
- Функции для доступа к входным регистрам по глобальным адресам
Модуль обработки команды чтения input registers (0x04): Модуль обработки команды чтения input registers (0x04):
- Чтение множественных входных регистров
Копирование данных из структур устройства в буфер ответа @section ivalid Валидация данных:
- Поддержка знаковых и беззнаковых значений - Проверка соответствия количества байт и регистров
- Валидация адресов через MB_DefineRegistersAddress()
- Обработка исключений при некорректных запросах
******************************************************************************/ ******************************************************************************/
#include "modbus_inputregs.h" #include "modbus_inputregs.h"
#ifdef MODBUS_ENABLE_INPUTS #ifdef MODBUS_ENABLE_INPUTS
/**
* @brief Записать входной регистр по глобальному адресу.
* @param Addr Адрес регистра.
* @param WriteVal Число для записи.
* @return ExceptionCode Код исключения если регистра по адресу не существует, и ET_NO_ERRORS если все ок.
*
* @details Позволяет обратиться к любому регистру по его глобальному адрессу.
Вне зависимости от того как регистры размещены в памяти.
*/
MB_ExceptionTypeDef MB_Input_Write_Global(uint16_t Addr, uint16_t WriteVal)
{
//---------CHECK FOR ERRORS----------
MB_ExceptionTypeDef Exception = ET_NO_ERRORS;
uint16_t *pInRegs;
//------------WRITE COIL-------------
Exception = MB_DefineRegistersAddress(&pInRegs, Addr, 1, RegisterType_Input, 1);
if(Exception == ET_NO_ERRORS)
{
*(pInRegs) = WriteVal;
}
return Exception;
}
/**
* @brief Считать входной регистр по глобальному адресу.
* @param Addr Адрес регистра.
* @param Exception Указатель на переменную для кода исключения, в случае неудачи при чтении.
* @return uint16_t Возвращает значение регистра.
*
* @details Позволяет обратиться к любому регистру по его глобальному адрессу.
Вне зависимости от того как регистры размещены в памяти.
*/
uint16_t MB_Input_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception)
{
//---------CHECK FOR ERRORS----------
MB_ExceptionTypeDef Exception_tmp = 0;
uint16_t *pInRegs;
//------------READ COIL--------------
Exception_tmp = MB_DefineRegistersAddress(&pInRegs, Addr, 1, RegisterType_Input, 0);
if(Exception) // if exception is not given to func fill it
*Exception = Exception_tmp;
if(Exception_tmp == ET_NO_ERRORS)
{
return *(pInRegs);
}
else
{
return 0;
}
}
/** /**
* @brief Обработать функцию Read Input Registers (04 - 0x04). * @brief Обработать функцию Read Input Registers (04 - 0x04).
* @param modbus_msg Указатель на структуру собщения modbus. * @param modbus_msg Указатель на структуру собщения modbus.
@@ -25,8 +89,8 @@ 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
uint16_t *pInRegs; uint16_t *pInRegs;
modbus_msg->Except_Code = MB_DefineRegistersAddress(&pInRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Input); // определение адреса регистров modbus_msg->Except_Code = MB_DefineRegistersAddress(&pInRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Input, 0); // определение адреса регистров
if(modbus_msg->Except_Code != NO_ERRORS) if(modbus_msg->Except_Code != ET_NO_ERRORS)
return 0; return 0;
@@ -38,15 +102,11 @@ uint8_t MB_Process_Read_Input_Regs(RS_MsgTypeDef *modbus_msg)
for (i = 0; i<modbus_msg->Qnt; i++) for (i = 0; i<modbus_msg->Qnt; i++)
{ {
if(*((int16_t *)pInRegs) > 0) if(*((int16_t *)pInRegs) > 0)
modbus_msg->DATA[i] = (*pInRegs++); modbus_msg->MbData[i] = (*pInRegs++);
else else
modbus_msg->DATA[i] = (*pInRegs++); modbus_msg->MbData[i] = (*pInRegs++);
} }
return 1; return 1;
} }
#else //MODBUS_ENABLE_INPUTS #endif //MODBUS_ENABLE_INPUTS
uint8_t MB_Process_Read_Input_Regs(RS_MsgTypeDef *modbus_msg) {return 0;}
#endif

View File

@@ -1,12 +1,22 @@
/** /**
************************************************************************** *******************************************************************************
* @file modbus_master.c * @file modbus_master.c
* @brief Модуль для реализации мастера MODBUS. * @brief Модуль для реализации мастера MODBUS.
************************************************************************** *******************************************************************************
* @details * @details
Файл содержит реализацию функций для работы Modbus в режиме мастера. Файл содержит реализацию функций для работы Modbus в режиме мастера.
@section Функции и макросы @section mast Функции и макросы
- MB_RespGet_RegisterAll() — Считать все регистра из ответа
- MB_RespGet_RegisterValue() — Считать один регистр из ответа
- MB_RespGet_CoilAll() — Считать все коилы из ответа
- MB_RespGet_CoilState() — Считать один коил из ответа
- MB_RespGet_NumberOfObjects() — Считать количество принятых объектов идентификатора
- MB_RespGet_ObjectById() — Считать объект идентификатора по
его ID
- MB_RespGet_ObjectByIndex() — Считать объект идентификатора по
порядковому номеру в сообщении
- MB_RespGet_Diagnostic() — Считать запрошенный диагностический счетчик
- MB_Master_Collect_Message() — Сбор сообщения в режиме мастера - MB_Master_Collect_Message() — Сбор сообщения в режиме мастера
- MB_Master_Parse_Message() — Парс сообщения в режиме мастера - MB_Master_Parse_Message() — Парс сообщения в режиме мастера
@@ -16,8 +26,35 @@
#ifdef MODBUS_ENABLE_MASTER #ifdef MODBUS_ENABLE_MASTER
//-------------------------------------------------------------------
//-----------------------------FOR USER------------------------------
/** /**
* @brief Получить значение регистра из ответа по его адресу * @brief Получить значение ВСЕХ регистров в ответе
* @param modbus_msg Указатель на структуру сообщения
* @param reg_addr Адрес регистра, значение которого нужно получить
* @param reg_arr Указатель для массив для сохранения значений регистров
* @return количество считанных регистров, 0 - ошибка
*/
int MB_RespGet_RegisterAll(RS_MsgTypeDef *modbus_msg, uint16_t *reg_arr)
{
if(modbus_msg == NULL || reg_arr == NULL)
return 0;
int read_cnt = 0;
int i = 0;
for(int addr = modbus_msg->Addr; addr < modbus_msg->Addr + modbus_msg->Qnt; addr++)
{
if(MB_RespGet_RegisterValue(modbus_msg, addr, &reg_arr[i]))
{
read_cnt++;
}
i++;
}
return read_cnt;
}
/**
* @brief Получить значение регистра в ответе по его адресу
* @param modbus_msg Указатель на структуру сообщения * @param modbus_msg Указатель на структуру сообщения
* @param reg_addr Адрес регистра, значение которого нужно получить * @param reg_addr Адрес регистра, значение которого нужно получить
* @param reg_value Указатель для значения регистра * @param reg_value Указатель для значения регистра
@@ -29,9 +66,9 @@ int MB_RespGet_RegisterValue(RS_MsgTypeDef *modbus_msg, uint16_t reg_addr, uint1
return 0; return 0;
// Проверяем что ответ связан с регистрами // Проверяем что ответ связан с регистрами
if((modbus_msg->Func_Code != MB_R_DISC_IN) && if((modbus_msg->FuncCode != FC_R_DISC_IN) &&
(modbus_msg->Func_Code != MB_R_HOLD_REGS) && (modbus_msg->FuncCode != FC_R_HOLD_REGS) &&
(modbus_msg->Func_Code != MB_R_IN_REGS)) (modbus_msg->FuncCode != FC_R_IN_REGS))
{ {
return 0; return 0;
} }
@@ -48,11 +85,237 @@ int MB_RespGet_RegisterValue(RS_MsgTypeDef *modbus_msg, uint16_t reg_addr, uint1
return 0; return 0;
// Получаем значение регистра // Получаем значение регистра
*reg_value = modbus_msg->DATA[reg_index]; *reg_value = modbus_msg->MbData[reg_index];
return 1; return 1;
} }
/**
* @brief Получить состояние ВСЕХ coil в ответе
* @param modbus_msg Указатель на структуру сообщения
* @param coil_arr Указатель для массив доя сохранения состояний coil (1 - ON, 0 - OFF)
* @return 1 - успех, 0 - ошибка или coil_addr вне диапазона запроса
*/
int MB_RespGet_CoilAll(RS_MsgTypeDef *modbus_msg, int *coil_arr)
{
if(modbus_msg == NULL || coil_arr == NULL)
return 0;
int read_cnt = 0;
int i = 0;
for(int addr = modbus_msg->Addr; addr < modbus_msg->Addr + modbus_msg->Qnt; addr++)
{
if(MB_RespGet_CoilState(modbus_msg, addr, &coil_arr[i]))
{
read_cnt++;
}
i++;
}
return 1;
}
/**
* @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->FuncCode != FC_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->MbData[data_index] >> (bit_index+8)) & 0x01;
else
*coil_state = ((modbus_msg->MbData[data_index]&0xFF) >> (bit_index-8)) & 0x01;
return 1;
}
/**
* @brief Получить количество объектов в сообщении
* @param modbus_msg Указатель на структуру сообщения
* @return int Количество объектов
*/
int MB_RespGet_NumberOfObjects(RS_MsgTypeDef *modbus_msg)
{
if(modbus_msg == NULL)
{
return 0;
}
// Проверяем что ответ связан с диагностикой
if(modbus_msg->FuncCode != FC_R_DEVICE_ID)
{
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->FuncCode != FC_R_DEVICE_ID)
{
return 0;
}
uint8_t *data = (uint8_t*)modbus_msg->MbData;
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->FuncCode != FC_R_DEVICE_ID)
{
return 0;
}
if(index >= modbus_msg->DevId.NumbOfObj)
return 0;
uint8_t *data = (uint8_t*)modbus_msg->MbData;
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 Получить данные диагностики из сообщения (MbData[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->FuncCode != FC_R_DIAGNOSTICS)
{
return 0;
}
*data = modbus_msg->MbData[1];
return 1;
}
//-------------------------------------------------------------------
//-----------------------------INTERNAL------------------------------
/** /**
* @brief Определить размер модбас запроса (МАСТЕР версия). * @brief Определить размер модбас запроса (МАСТЕР версия).
* @param hRS Указатель на хендлер RS. * @param hRS Указатель на хендлер RS.
@@ -67,24 +330,24 @@ static int MB_Define_Size_of_Function(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *
// Master mode - calculating response size from slave // Master mode - calculating response size from slave
if (modbus_msg->Func_Code & ERR_VALUES_START) if (modbus_msg->FuncCode & FC_ERR_VALUES_START)
{ {
// Error response: [Addr][Func|0x80][ExceptCode][CRC] // Error response: [Addr][Func|0x80][ExceptCode][CRC]
mb_func_size = -1; // Only Exception Code mb_func_size = -1; // Only Exception Code
} }
else if (modbus_msg->Func_Code == MB_R_DIAGNOSTIC) else if (modbus_msg->FuncCode == FC_R_DIAGNOSTICS)
{ {
// Diagnostics response: [SubFunc_HI][SubFunc_LO][Data_HI][Data_LO] // Diagnostics response: [SubFunc_HI][SubFunc_LO][Data_HI][Data_LO]
mb_func_size = 1; mb_func_size = 1;
} }
else if (modbus_msg->Func_Code == MB_R_DEVICE_INFO) else if (modbus_msg->FuncCode == FC_R_DEVICE_ID)
{ {
// Device identifications: variable size, need to read first to determine // Device identifications: variable size, need to read first to determine
mb_func_size = 0; // Will be determined after reading header mb_func_size = 0; // Will be determined after reading header
} }
else else
{ {
switch (modbus_msg->Func_Code & ~ERR_VALUES_START) switch (modbus_msg->FuncCode & ~FC_ERR_VALUES_START)
{ {
case 0x01: // Read Coils case 0x01: // Read Coils
case 0x02: // Read Discrete Inputs case 0x02: // Read Discrete Inputs
@@ -111,7 +374,7 @@ static int MB_Define_Size_of_Function(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *
} }
} }
mb_func_size = RX_FIRST_PART_SIZE + mb_func_size; // size of whole message mb_func_size = RS_RX_FIRST_PART_SIZE + mb_func_size; // size of whole message
return mb_func_size; return mb_func_size;
} }
@@ -129,28 +392,33 @@ RS_StatusTypeDef MB_Master_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgType
//------INFO ABOUT DATA/MESSAGE------ //------INFO ABOUT DATA/MESSAGE------
//-----------[first bytes]----------- //-----------[first bytes]-----------
// set ID of slave device // set ID of slave device
modbus_uart_buff[ind++] = modbus_msg->MbAddr; modbus_uart_buff[ind++] = modbus_msg->DeviceAddr;
// set function code // set function code
modbus_uart_buff[ind++] = modbus_msg->Func_Code; modbus_uart_buff[ind++] = modbus_msg->FuncCode;
if(modbus_msg->Func_Code < ERR_VALUES_START) // if no error occur if(modbus_msg->FuncCode < FC_ERR_VALUES_START) // if no error occur
{ {
// fill modbus header // fill modbus header
if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) // device identifications request if(0) {}
#ifdef MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
else if(modbus_msg->FuncCode == FC_R_DEVICE_ID) // device identifications request
{ {
modbus_uart_buff[ind++] = modbus_msg->DevId.MEI_Type; modbus_uart_buff[ind++] = modbus_msg->DevId.MEI_Type;
modbus_uart_buff[ind++] = modbus_msg->DevId.ReadDevId; modbus_uart_buff[ind++] = modbus_msg->DevId.ReadDevId;
modbus_uart_buff[ind++] = modbus_msg->DevId.NextObjId; modbus_uart_buff[ind++] = modbus_msg->DevId.NextObjId;
} }
else if(modbus_msg->Func_Code == MB_R_DIAGNOSTIC) #endif //MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
#ifdef MODBUS_ENABLE_DIAGNOSTICS
else if(modbus_msg->FuncCode == FC_R_DIAGNOSTICS)
{ {
// Diagnostics: [SubFunc_HI][SubFunc_LO][Data_HI][Data_LO] // 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->MbData[0] >> 8; // Sub-function HI
modbus_uart_buff[ind++] = modbus_msg->DATA[0] & 0xFF; // Sub-function LO modbus_uart_buff[ind++] = modbus_msg->MbData[0] & 0xFF; // Sub-function LO
modbus_uart_buff[ind++] = modbus_msg->DATA[1] >> 8; // Data HI modbus_uart_buff[ind++] = modbus_msg->MbData[1] >> 8; // Data HI
modbus_uart_buff[ind++] = modbus_msg->DATA[1] & 0xFF; // Data LO modbus_uart_buff[ind++] = modbus_msg->MbData[1] & 0xFF; // Data LO
} }
#endif //MODBUS_ENABLE_DIAGNOSTICS
else // classic modbus request else // classic modbus request
{ {
// set address // set address
@@ -162,12 +430,12 @@ RS_StatusTypeDef MB_Master_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgType
modbus_uart_buff[ind++] = modbus_msg->Qnt & 0xFF; modbus_uart_buff[ind++] = modbus_msg->Qnt & 0xFF;
// for write multiple functions // for write multiple functions
if((modbus_msg->Func_Code == 0x0F) || (modbus_msg->Func_Code == 0x10)) if((modbus_msg->FuncCode == 0x0F) || (modbus_msg->FuncCode == 0x10))
{ {
modbus_uart_buff[ind++] = modbus_msg->ByteCnt; modbus_uart_buff[ind++] = modbus_msg->ByteCnt;
// write data bytes // write data bytes
uint8_t *tmp_data_addr = (uint8_t *)modbus_msg->DATA; uint8_t *tmp_data_addr = (uint8_t *)modbus_msg->MbData;
for(int i = 0; i < modbus_msg->ByteCnt; i++) for(int i = 0; i < modbus_msg->ByteCnt; i++)
{ {
modbus_uart_buff[ind++] = tmp_data_addr[i]; modbus_uart_buff[ind++] = tmp_data_addr[i];
@@ -182,7 +450,7 @@ RS_StatusTypeDef MB_Master_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgType
//---------------CRC---------------- //---------------CRC----------------
//---------[last 2 bytes]---------- //---------[last 2 bytes]----------
uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind); uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind);
modbus_msg->MB_CRC = CRC_VALUE; modbus_msg->MbCRC = CRC_VALUE;
modbus_uart_buff[ind++] = CRC_VALUE & 0xFF; modbus_uart_buff[ind++] = CRC_VALUE & 0xFF;
modbus_uart_buff[ind++] = CRC_VALUE >> 8; modbus_uart_buff[ind++] = CRC_VALUE >> 8;
@@ -204,18 +472,20 @@ RS_StatusTypeDef MB_Master_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDe
int expected_size = 0; int expected_size = 0;
// get ID of slave device // get ID of slave device
modbus_msg->MbAddr = modbus_uart_buff[ind++]; modbus_msg->DeviceAddr = modbus_uart_buff[ind++];
// get function code (check if error response) // get function code (check if error response)
modbus_msg->Func_Code = modbus_uart_buff[ind++]; modbus_msg->FuncCode = modbus_uart_buff[ind++];
if(modbus_msg->Func_Code & ERR_VALUES_START) // error response if(modbus_msg->FuncCode & FC_ERR_VALUES_START) // error response
{ {
modbus_msg->Except_Code = modbus_uart_buff[ind++]; modbus_msg->Except_Code = modbus_uart_buff[ind++];
} }
else if(modbus_msg->Func_Code < ERR_VALUES_START) // normal response else if(modbus_msg->FuncCode < FC_ERR_VALUES_START) // normal response
{ {
if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) // device identifications response if(0) {}
#ifdef MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
else if(modbus_msg->FuncCode == FC_R_DEVICE_ID) // device identifications response
{ {
modbus_msg->DevId.MEI_Type = modbus_uart_buff[ind++]; modbus_msg->DevId.MEI_Type = modbus_uart_buff[ind++];
modbus_msg->DevId.ReadDevId = modbus_uart_buff[ind++]; modbus_msg->DevId.ReadDevId = modbus_uart_buff[ind++];
@@ -227,7 +497,7 @@ RS_StatusTypeDef MB_Master_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDe
modbus_msg->ByteCnt = 0; modbus_msg->ByteCnt = 0;
// Парсинг объектов идентификации устройства // Парсинг объектов идентификации устройства
uint8_t *tmp_data_addr = (uint8_t *)modbus_msg->DATA; uint8_t *tmp_data_addr = (uint8_t *)modbus_msg->MbData;
int data_index = 0; int data_index = 0;
for(int obj = 0; obj < modbus_msg->DevId.NumbOfObj; obj++) for(int obj = 0; obj < modbus_msg->DevId.NumbOfObj; obj++)
@@ -249,24 +519,27 @@ RS_StatusTypeDef MB_Master_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDe
modbus_msg->ByteCnt += (2 + object_length); // ID + длина + данные modbus_msg->ByteCnt += (2 + object_length); // ID + длина + данные
} }
} }
else if(modbus_msg->Func_Code == MB_R_DIAGNOSTIC) #endif //MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
#ifdef MODBUS_ENABLE_DIAGNOSTICS
else if(modbus_msg->FuncCode == FC_R_DIAGNOSTICS)
{ {
// Diagnostics response: [SubFunc_HI][SubFunc_LO][Data_HI][Data_LO] // Diagnostics response: [SubFunc_HI][SubFunc_LO][Data_HI][Data_LO]
modbus_msg->DATA[0] = modbus_uart_buff[ind++] << 8; modbus_msg->MbData[0] = modbus_uart_buff[ind++] << 8;
modbus_msg->DATA[0] |= modbus_uart_buff[ind++]; modbus_msg->MbData[0] |= modbus_uart_buff[ind++];
modbus_msg->DATA[1] = modbus_uart_buff[ind++] << 8; modbus_msg->MbData[1] = modbus_uart_buff[ind++] << 8;
modbus_msg->DATA[1] |= modbus_uart_buff[ind++]; modbus_msg->MbData[1] |= modbus_uart_buff[ind++];
} }
#endif //MODBUS_ENABLE_DIAGNOSTICS
else // classic modbus response else // classic modbus response
{ {
// get byte count for read functions // get byte count for read functions
if((modbus_msg->Func_Code == 0x01) || (modbus_msg->Func_Code == 0x02) || if((modbus_msg->FuncCode == 0x01) || (modbus_msg->FuncCode == 0x02) ||
(modbus_msg->Func_Code == 0x03) || (modbus_msg->Func_Code == 0x04)) (modbus_msg->FuncCode == 0x03) || (modbus_msg->FuncCode == 0x04))
{ {
modbus_msg->ByteCnt = modbus_uart_buff[ind++]; modbus_msg->ByteCnt = modbus_uart_buff[ind++];
// read data bytes // read data bytes
uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->DATA; uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->MbData;
for(int i = 0; i < modbus_msg->ByteCnt; i++) for(int i = 0; i < modbus_msg->ByteCnt; i++)
{ {
if(i % 2 == 0) // HI byte if(i % 2 == 0) // HI byte
@@ -276,8 +549,8 @@ RS_StatusTypeDef MB_Master_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDe
} }
} }
// for write functions - echo address and quantity // for write functions - echo address and quantity
else if((modbus_msg->Func_Code == 0x05) || (modbus_msg->Func_Code == 0x06) || else if((modbus_msg->FuncCode == 0x05) || (modbus_msg->FuncCode == 0x06) ||
(modbus_msg->Func_Code == 0x0F) || (modbus_msg->Func_Code == 0x10)) (modbus_msg->FuncCode == 0x0F) || (modbus_msg->FuncCode == 0x10))
{ {
modbus_msg->Addr = modbus_uart_buff[ind++] << 8; modbus_msg->Addr = modbus_uart_buff[ind++] << 8;
modbus_msg->Addr |= modbus_uart_buff[ind++]; modbus_msg->Addr |= modbus_uart_buff[ind++];
@@ -291,10 +564,10 @@ RS_StatusTypeDef MB_Master_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDe
//---------------CRC---------------- //---------------CRC----------------
//----------[last 2 bytes]---------- //----------[last 2 bytes]----------
uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind); uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind);
modbus_msg->MB_CRC = modbus_uart_buff[ind++]; modbus_msg->MbCRC = modbus_uart_buff[ind++];
modbus_msg->MB_CRC |= modbus_uart_buff[ind++] << 8; modbus_msg->MbCRC |= modbus_uart_buff[ind++] << 8;
if(modbus_msg->MB_CRC != CRC_VALUE) if(modbus_msg->MbCRC != CRC_VALUE)
{ {
TrackerCnt_Err(hmodbus->rs_err); TrackerCnt_Err(hmodbus->rs_err);
return RS_PARSE_MSG_ERR; return RS_PARSE_MSG_ERR;
@@ -310,58 +583,58 @@ RS_StatusTypeDef MB_Master_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDe
/** @brief Сформировать запрос на чтение коилов */ /** @brief Сформировать запрос на чтение коилов */
RS_MsgTypeDef MB_REQUEST_READ_COILS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity) 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}; RS_MsgTypeDef msg = {slave_addr, FC_R_COILS, {0}, start_addr, quantity, 0, {0}, 0, 0};
return msg; return msg;
} }
/** @brief Сформировать запрос на чтение дискретных регистров */ /** @brief Сформировать запрос на чтение дискретных регистров */
RS_MsgTypeDef MB_REQUEST_READ_DISCRETE_INPUTS(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 msg = {slave_addr, MB_R_DISC_IN, {0}, start_addr, quantity, 0, {0}, 0, 0}; RS_MsgTypeDef msg = {slave_addr, FC_R_DISC_IN, {0}, start_addr, quantity, 0, {0}, 0, 0};
return msg; return msg;
} }
/** @brief Сформировать запрос на чтение холдинг регистров */ /** @brief Сформировать запрос на чтение холдинг регистров */
RS_MsgTypeDef MB_REQUEST_READ_HOLDING_REGS(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 msg = {slave_addr, MB_R_HOLD_REGS, {0}, start_addr, quantity, 0, {0}, 0, 0}; RS_MsgTypeDef msg = {slave_addr, FC_R_HOLD_REGS, {0}, start_addr, quantity, 0, {0}, 0, 0};
return msg; return msg;
} }
/** @brief Сформировать запрос на чтение инпут регистров */ /** @brief Сформировать запрос на чтение инпут регистров */
RS_MsgTypeDef MB_REQUEST_READ_INPUT_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 msg = {slave_addr, MB_R_IN_REGS, {0}, start_addr, quantity, 0, {0}, 0, 0}; RS_MsgTypeDef msg = {slave_addr, FC_R_IN_REGS, {0}, start_addr, quantity, 0, {0}, 0, 0};
return msg; return msg;
} }
/** @brief Сформировать запрос на запись одного коила */ /** @brief Сформировать запрос на запись одного коила */
RS_MsgTypeDef MB_REQUEST_WRITE_SINGLE_COIL(uint8_t slave_addr, uint16_t coil_addr, uint8_t value) 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}; RS_MsgTypeDef msg = {slave_addr, FC_W_COIL, {0}, coil_addr, (value ? 0xFF00 : 0x0000), 0, {0}, 0, 0};
return msg; return msg;
} }
/** @brief Сформировать запрос на запись одного регистра */ /** @brief Сформировать запрос на запись одного регистра */
RS_MsgTypeDef MB_REQUEST_WRITE_SINGLE_REG(uint8_t slave_addr, uint16_t reg_addr, uint16_t value) 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}; RS_MsgTypeDef msg = {slave_addr, FC_W_HOLD_REG, {0}, reg_addr, value, 0, {0}, 0, 0};
return msg; return msg;
} }
/** @brief Сформировать запрос на запись нескольких регистров */ /** @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 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}; RS_MsgTypeDef msg = {slave_addr, FC_W_COILS, {0}, start_addr, quantity, 0, {0}, 0, 0};
// Calculate byte count and prepare data // Calculate byte count and prepare data
uint8_t byte_count = (quantity + 7) / 8; uint8_t byte_count = (quantity + 7) / 8;
msg.ByteCnt = byte_count; msg.ByteCnt = byte_count;
// Copy coil data to message DATA array // Copy coil data to message MbData array
for(int i = 0; i < byte_count; i++) { for(int i = 0; i < byte_count; i++) {
if(i < DATA_SIZE) { if(i < MbData_size) {
msg.DATA[i] = coils_data[i]; msg.MbData[i] = coils_data[i];
} }
} }
@@ -371,13 +644,13 @@ RS_MsgTypeDef MB_REQUEST_WRITE_MULTIPLE_COILS(uint8_t slave_addr, uint16_t start
/** @brief Сформировать запрос на запись нескольких коилов */ /** @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 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}; RS_MsgTypeDef msg = {slave_addr, FC_W_HOLD_REGS, {0}, start_addr, quantity, 0, {0}, 0, 0};
msg.ByteCnt = quantity * 2; // Each register is 2 bytes msg.ByteCnt = quantity * 2; // Each register is 2 bytes
// Copy register data to message DATA array // Copy register data to message MbData array
for(int i = 0; i < quantity && i < DATA_SIZE; i++) { for(int i = 0; i < quantity && i < MbData_size; i++) {
msg.DATA[i] = regs_data[i]; msg.MbData[i] = regs_data[i];
} }
return msg; return msg;
@@ -386,7 +659,7 @@ RS_MsgTypeDef MB_REQUEST_WRITE_MULTIPLE_REGS(uint8_t slave_addr, uint16_t start_
//---------ДИАГНОСТИЧЕСКИЕ ДАННЫЕ----------- //---------ДИАГНОСТИЧЕСКИЕ ДАННЫЕ-----------
RS_MsgTypeDef MB_REQUEST_DIAGNOSTIC_QUERY(uint8_t slave_addr, uint16_t sub_function, uint16_t data) 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}; RS_MsgTypeDef msg = {slave_addr, FC_R_DIAGNOSTICS, {0}, 0, 0, 0, {sub_function, data}, 0, 0};
return msg; return msg;
} }
RS_MsgTypeDef MB_REQUEST_RETURN_QUERY_DATA(uint8_t slave_addr) RS_MsgTypeDef MB_REQUEST_RETURN_QUERY_DATA(uint8_t slave_addr)
@@ -457,71 +730,26 @@ 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_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}; RS_MsgTypeDef msg = {slave_addr, FC_R_DEVICE_ID, {0x0E, 0x01, 0x00, 0, 0, 0}, 0, 0, 0, {0}, 0, 0};
return msg; return msg;
} }
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_REGULAR(uint8_t slave_addr) 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}; RS_MsgTypeDef msg = {slave_addr, FC_R_DEVICE_ID, {0x0E, 0x02, 0x00, 0, 0, 0}, 0, 0, 0, {0}, 0, 0};
return msg; return msg;
} }
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_EXTENDED(uint8_t slave_addr) 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}; RS_MsgTypeDef msg = {slave_addr, FC_R_DEVICE_ID, {0x0E, 0x03, 0x00, 0, 0, 0}, 0, 0, 0, {0}, 0, 0};
return msg; return msg;
} }
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_SPECIFIC(uint8_t slave_addr, uint8_t object_id) 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}; RS_MsgTypeDef msg = {slave_addr, FC_R_DEVICE_ID, {0x0E, 0x04, object_id, 0, 0, 0}, 0, 0, 0, {0}, 0, 0};
return msg; return msg;
} }
#endif //MODBUS_ENABLE_MASTER
#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

145
Src/modbus_oscil.c Normal file
View File

@@ -0,0 +1,145 @@
/**
*******************************************************************************
* @file modbus_oscil.c
* @brief Модуль для реализации осциллографа через MODBUS.
*******************************************************************************
* @details
* Файл содержит реализацию функций для работы с буфером осциллографа.
*
* @section oscil_functions Функции
* - MB_Oscil_Init() — Инициализация структуры осциллографа
* - MB_Oscil_Add() — Добавление данных в буфер
* - MB_Oscil_UpdateTail() — Обновление указателя Tail
******************************************************************************/
#include "modbus_oscil.h"
#ifdef MODBUS_ENABLE_OSCIL
/**
* @brief Инициализация структуры осциллографа
* @param oscil Указатель на структуру осциллографа
* @param BufferSize Размер буфера в Modbus регистрах (max 125)
* @param NumbOfChannels Количество каналов (должно быть четным)
* @param SampleTime Период дискретизации
* @return HAL Status
*/
HAL_StatusTypeDef MB_Oscil_Init(MB_OscilTypeDef *oscil, uint8_t BufferSize, uint8_t NumbOfChannels, uint16_t SampleTime)
{
if(!oscil || (BufferSize >= MbData_size) || (NumbOfChannels > 15) || !SampleTime)
return HAL_ERROR;
if(NumbOfChannels % 2 != 0)
return HAL_ERROR;
oscil->Config.BufferSize = BufferSize;
oscil->Config.NumbOfChannels = NumbOfChannels;
oscil->Config.SampleTime = SampleTime;
oscil->Config.LastTick = 0;
oscil->Preamble.Head = 0;
oscil->Preamble.Tail = 0;
oscil->Config.Overrun = 0;
return HAL_OK;
}
/**
* @brief Инициализация структуры осциллографа
* @param oscil Указатель на структуру осциллографа
* @param BufferSize Размер буфера в Modbus регистрах (max 125)
* @param NumbOfChannels Количество каналов (должно быть четным)
* @param SampleTime Период дискретизации
* @return HAL Status
*/
HAL_StatusTypeDef MB_Oscil_Set_SampleTime(MB_OscilTypeDef *oscil, uint16_t SampleTime)
{
if(!oscil || !SampleTime)
return HAL_ERROR;
oscil->Config.SampleTime = SampleTime;
return HAL_OK;
}
/**
* @brief Добавление данных всех каналов в буфер
* @param oscil Указатель на структуру осциллографа
* @param Data Массив с данными каналов (длина = NumbOfChannels)
* @return HAL Status
*/
HAL_StatusTypeDef MB_Oscil_Add(MB_OscilTypeDef *oscil, uint8_t *Data)
{
if(!oscil || !Data)
return HAL_ERROR;
if(local_time() - oscil->Config.LastTick < oscil->Config.SampleTime)
return HAL_BUSY;
oscil->Config.LastTick = local_time();
uint8_t head_max = oscil->Config.BufferSize * 2;
uint8_t start_pos = oscil->Preamble.Head;
uint8_t channels = oscil->Config.NumbOfChannels;
uint8_t tail = oscil->Preamble.Tail;
// Пишем данные
for(uint8_t i = 0; i < channels; i++)
{
uint8_t write_pos = (start_pos + i) % head_max;
oscil->Data[write_pos] = Data[i];
}
// Новое положение Head
uint8_t new_head = (start_pos + channels) % head_max;
// Проверяем, есть ли непрочитанные данные (Tail != Head)
// if(tail != start_pos) {
// Если есть непрочитанные данные, проверяем не перетерли ли мы их
if(start_pos < new_head) {
// Линейный случай
if(tail > start_pos && tail <= new_head) {
oscil->Preamble.Tail = (new_head + 1) % head_max;
oscil->Config.Overrun = 1;
}
} else if(start_pos > new_head) {
// Кольцевой случай (было переполнение)
if(tail > start_pos || tail <= new_head) {
oscil->Preamble.Tail = (new_head + 1) % head_max;
oscil->Config.Overrun = 1;
}
}
// }
oscil->Preamble.Head = new_head;
return HAL_OK;
}
/**
* @brief Обновление указателя Tail
* @param oscil Указатель на структуру осциллографа
* @return HAL Status
*
* @details Вызывается после того, как данные были прочитаны через Modbus.
* Tail устанавливается на следующий байт за Head.
*/
HAL_StatusTypeDef MB_Oscil_UpdateTail(MB_OscilTypeDef *oscil)
{
if(!oscil)
return HAL_ERROR;
// Сдвигаем Tail на следующий байт за Head
uint8_t head_max = oscil->Config.BufferSize * 2;
oscil->Preamble.Tail = oscil->Preamble.Head;
if(oscil->Preamble.Tail >= head_max)
oscil->Preamble.Tail = 0;
oscil->Config.Overrun = 0;
return HAL_OK;
}
#endif //MODBUS_ENABLE_OSCIL

View File

@@ -1,12 +1,14 @@
/** /**
************************************************************************** *******************************************************************************
* @file modbus_slave.c * @file modbus_slave.c
* @brief Модуль для реализации слейв MODBUS. * @brief Модуль для реализации слейв MODBUS.
************************************************************************** *******************************************************************************
* @details * @details
Файл содержит реализацию функций для работы Modbus в режиме слейва. Файл содержит реализацию функций для работы Modbus в режиме слейва.
@section Функции и макросы @section slave Функции и макросы
- MB_Slave_ResponseLater() — Выставить флаг на ответ вне прерывания
- MB_Slave_SendResponse() — Ответить на запрос
- MB_Slave_Response() — Ответ на запрос - MB_Slave_Response() — Ответ на запрос
- MB_Slave_Collect_Message() — Сбор сообщения в режиме слейва. - MB_Slave_Collect_Message() — Сбор сообщения в режиме слейва.
@@ -15,6 +17,66 @@
#include "modbus.h" #include "modbus.h"
#ifdef MODBUS_ENABLE_SLAVE #ifdef MODBUS_ENABLE_SLAVE
/**
* @brief Ответить позже, не в прерывании.
* @param hmodbus Указатель на хендлер RS.
* @param ResponseCode Код запроса на который надо ответить.
* @return HAL Status.
* @details Отменяет ответ в прерывании на запрос.
Используется вместе с @ref MB_Slave_SendResponse
*/
HAL_StatusTypeDef MB_Slave_ResponseLater(RS_HandleTypeDef *hmodbus, uint8_t ResponseCode)
{
hmodbus->f.DeferredResponse = ResponseCode;
return HAL_OK;
}
/**
* @brief Ответить на запрос.
* @param hmodbus Указатель на хендлер RS.
* @param ResponseCode Код запроса на который надо ответить.
* @param error Тип ошибки или её отсутствия в ответе.
* @return HAL Status.
* @details Ответить на запрос вне прерывания.
Используется вместе с @ref MB_Slave_ResponseLater
*/
HAL_StatusTypeDef MB_Slave_SendResponse(RS_HandleTypeDef *hmodbus, uint8_t ResponseCode, MB_ExceptionTypeDef error)
{
RS_StatusTypeDef MB_RES = 0;
if(hmodbus->f.DeferredResponse == ResponseCode)
{
hmodbus->f.DeferredResponse = 0;
switch(error)
{
case ET_NO_ERRORS:
break;
case ET_ACKNOWLEDGE:
MB_Diagnostics_SlaveNAKCnt();
break;
case ET_SLAVE_DEVICE_BUSY:
MB_Diagnostics_SlaveBusyCnt();
break;
default:
break;
}
if(error != ET_NO_ERRORS)
{
MB_Diagnostics_ExceptionErrorCnt();
TrackerCnt_Warn(hmodbus->rs_err);
hmodbus->pMessagePtr->FuncCode |= FC_ERR_VALUES_START;
hmodbus->pMessagePtr->Except_Code = error;
}
hmodbus->RS_STATUS = RS_Handle_Transmit_Start(hmodbus, hmodbus->pMessagePtr);
}
return HAL_OK;
}
/** /**
* @brief Ответ на сообщение в режиме слейва. * @brief Ответ на сообщение в режиме слейва.
* @param hmodbus Указатель на хендлер RS. * @param hmodbus Указатель на хендлер RS.
@@ -29,7 +91,7 @@ RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mod
RS_Reset_TX_Flags(hmodbus); // reset flag for correct transmit RS_Reset_TX_Flags(hmodbus); // reset flag for correct transmit
MB_Diagnostics_BusMessageCnt(); MB_Diagnostics_BusMessageCnt();
if(hmodbus->ID == 0 || modbus_msg->MbAddr == 0) if(hmodbus->ID == 0 || modbus_msg->DeviceAddr == 0)
{ {
MB_Diagnostics_SlaveNoResponseCnt(); // <-- Устройство не отвечает на широковещательные сообщения MB_Diagnostics_SlaveNoResponseCnt(); // <-- Устройство не отвечает на широковещательные сообщения
hmodbus->RS_STATUS = RS_SKIP; hmodbus->RS_STATUS = RS_SKIP;
@@ -37,26 +99,31 @@ RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mod
} }
MB_Diagnostics_SlaveMessageCnt(); MB_Diagnostics_SlaveMessageCnt();
if(modbus_msg->Func_Code < ERR_VALUES_START)// if no errors after parsing if(modbus_msg->FuncCode < FC_ERR_VALUES_START)// if no errors after parsing
{ {
switch (modbus_msg->Func_Code) switch (modbus_msg->FuncCode)
{ {
// Read Coils // Read Coils
case MB_R_COILS: case FC_R_COILS:
hmodbus->f.MessageHandled = MB_Process_Read_Coils(hmodbus->pMessagePtr); hmodbus->f.MessageHandled = MB_Process_Read_Coils(hmodbus->pMessagePtr);
break; break;
// Read Hodling Registers // Read Hodling Registers
case MB_R_HOLD_REGS: case FC_R_HOLD_REGS:
hmodbus->f.MessageHandled = MB_Process_Read_Hold_Regs(hmodbus->pMessagePtr); hmodbus->f.MessageHandled = MB_Process_Read_Hold_Regs(hmodbus->pMessagePtr);
#ifdef MODBUS_ENABLE_OSCIL
int is_oscil_data_register = ((hmodbus->pMessagePtr->Addr >= R_HOLDING_OSCIL_ADDR+4) && (hmodbus->pMessagePtr->Addr + hmodbus->pMessagePtr->Qnt <= (R_HOLDING_OSCIL_ADDR+5+(sizeof(MB_OscilTypeDef)/2))));
if(is_oscil_data_register)
MB_Oscil_UpdateTail(&MB_INTERNAL.oscil);
#endif
break; break;
case MB_R_IN_REGS: case FC_R_IN_REGS:
hmodbus->f.MessageHandled = MB_Process_Read_Input_Regs(hmodbus->pMessagePtr); hmodbus->f.MessageHandled = MB_Process_Read_Input_Regs(hmodbus->pMessagePtr);
break; break;
// Write Single Coils // Write Single Coils
case MB_W_COIL: case FC_W_COIL:
hmodbus->f.MessageHandled = MB_Process_Write_Single_Coil(hmodbus->pMessagePtr); hmodbus->f.MessageHandled = MB_Process_Write_Single_Coil(hmodbus->pMessagePtr);
if(hmodbus->f.MessageHandled) if(hmodbus->f.MessageHandled)
{ {
@@ -66,7 +133,7 @@ RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mod
} }
break; break;
case MB_W_HOLD_REG: case FC_W_HOLD_REG:
hmodbus->f.MessageHandled = MB_Process_Write_Single_Reg(hmodbus->pMessagePtr); hmodbus->f.MessageHandled = MB_Process_Write_Single_Reg(hmodbus->pMessagePtr);
if(hmodbus->f.MessageHandled) if(hmodbus->f.MessageHandled)
{ {
@@ -77,7 +144,7 @@ RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mod
break; break;
// Write Multiple Coils // Write Multiple Coils
case MB_W_COILS: case FC_W_COILS:
hmodbus->f.MessageHandled = MB_Process_Write_Miltuple_Coils(hmodbus->pMessagePtr); hmodbus->f.MessageHandled = MB_Process_Write_Miltuple_Coils(hmodbus->pMessagePtr);
if(hmodbus->f.MessageHandled) if(hmodbus->f.MessageHandled)
{ {
@@ -88,7 +155,7 @@ RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mod
break; break;
// Write Multiple Registers // Write Multiple Registers
case MB_W_HOLD_REGS: case FC_W_HOLD_REGS:
hmodbus->f.MessageHandled = MB_Process_Write_Miltuple_Regs(hmodbus->pMessagePtr); hmodbus->f.MessageHandled = MB_Process_Write_Miltuple_Regs(hmodbus->pMessagePtr);
if(hmodbus->f.MessageHandled) if(hmodbus->f.MessageHandled)
{ {
@@ -98,12 +165,12 @@ RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mod
} }
break; break;
case MB_R_DEVICE_INFO: case FC_R_DEVICE_ID:
hmodbus->f.MessageHandled = MB_Process_Read_Device_Identifications(hmodbus->pMessagePtr); hmodbus->f.MessageHandled = MB_Process_Read_Device_Identifications(hmodbus->pMessagePtr);
break; break;
// Добавить в switch-case после других case: // Добавить в switch-case после других case:
case MB_R_DIAGNOSTIC: case FC_R_DIAGNOSTICS:
hmodbus->f.MessageHandled = MB_Process_Diagnostics(hmodbus->pMessagePtr); hmodbus->f.MessageHandled = MB_Process_Diagnostics(hmodbus->pMessagePtr);
break; break;
@@ -112,7 +179,6 @@ RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mod
modbus_msg->Except_Code = 0x01; /* set exception code: illegal function */ modbus_msg->Except_Code = 0x01; /* set exception code: illegal function */
} }
// Проверяем режим устройства - если Listen Only, не обрабатываем команды // Проверяем режим устройства - если Listen Only, не обрабатываем команды
if (MB_GetDeviceMode() == MODBUS_LISTEN_ONLY_MODE) if (MB_GetDeviceMode() == MODBUS_LISTEN_ONLY_MODE)
{ {
@@ -126,7 +192,7 @@ RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mod
{ {
MB_Diagnostics_ExceptionErrorCnt(); MB_Diagnostics_ExceptionErrorCnt();
TrackerCnt_Warn(hmodbus->rs_err); TrackerCnt_Warn(hmodbus->rs_err);
modbus_msg->Func_Code |= ERR_VALUES_START; modbus_msg->FuncCode |= FC_ERR_VALUES_START;
} }
else else
{ {
@@ -147,8 +213,8 @@ RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mod
} }
else else
{ {
RS_Handle_Receive_Start(hmodbus, modbus_msg); // RS_Handle_Receive_Start(hmodbus, modbus_msg);
hmodbus->f.DeferredResponse = 0; // hmodbus->f.DeferredResponse = 0;
} }
hmodbus->RS_STATUS = MB_RES; hmodbus->RS_STATUS = MB_RES;
@@ -168,22 +234,34 @@ RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeD
{ {
int ind = 0; // ind for modbus-uart buffer int ind = 0; // ind for modbus-uart buffer
if(hmodbus->f.EchoResponse && hmodbus->f.MessageHandled) // if echo response need if(hmodbus->f.EchoResponse && (modbus_msg->Except_Code == ET_NO_ERRORS)) // if echo response need
ind = hmodbus->RS_Message_Size; ind = hmodbus->RS_Message_Size;
else else
{ {
//------INFO ABOUT DATA/MESSAGE------ //------INFO ABOUT DATA/MESSAGE------
#ifdef MODBUS_PROTOCOL_TCP
modbus_uart_buff[ind++] = modbus_msg->TransactionID >> 8;
modbus_uart_buff[ind++] = modbus_msg->TransactionID& 0xFF;
modbus_uart_buff[ind++] = modbus_msg->ProtocolID >> 8;
modbus_uart_buff[ind++] = modbus_msg->ProtocolID& 0xFF;
modbus_uart_buff[ind++] = modbus_msg->PDULength >> 8;
modbus_uart_buff[ind++] = modbus_msg->PDULength& 0xFF;
#endif
//-----------[first bytes]----------- //-----------[first bytes]-----------
// set ID of message/user // set ID of message/user
modbus_uart_buff[ind++] = modbus_msg->MbAddr; modbus_uart_buff[ind++] = modbus_msg->DeviceAddr;
// set dat or err response // set dat or err response
modbus_uart_buff[ind++] = modbus_msg->Func_Code; modbus_uart_buff[ind++] = modbus_msg->FuncCode;
if (modbus_msg->Func_Code < ERR_VALUES_START) // if no error occur if (modbus_msg->FuncCode < FC_ERR_VALUES_START) // if no error occur
{ {
// fill modbus header // fill modbus header
if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) // devide identifications header if(0) {}
#ifdef MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
else if(modbus_msg->FuncCode == FC_R_DEVICE_ID) // devide identifications header
{ {
modbus_uart_buff[ind++] = modbus_msg->DevId.MEI_Type; modbus_uart_buff[ind++] = modbus_msg->DevId.MEI_Type;
modbus_uart_buff[ind++] = modbus_msg->DevId.ReadDevId; modbus_uart_buff[ind++] = modbus_msg->DevId.ReadDevId;
@@ -192,7 +270,7 @@ RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeD
modbus_uart_buff[ind++] = modbus_msg->DevId.NextObjId; modbus_uart_buff[ind++] = modbus_msg->DevId.NextObjId;
modbus_uart_buff[ind++] = modbus_msg->DevId.NumbOfObj; modbus_uart_buff[ind++] = modbus_msg->DevId.NumbOfObj;
if (modbus_msg->ByteCnt > DATA_SIZE*2) // if ByteCnt less than DATA_SIZE if (modbus_msg->ByteCnt > MbData_size*2) // if ByteCnt less than MbData_size
{ {
TrackerCnt_Err(hmodbus->rs_err); TrackerCnt_Err(hmodbus->rs_err);
return RS_COLLECT_MSG_ERR; return RS_COLLECT_MSG_ERR;
@@ -201,7 +279,7 @@ RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeD
//---------------DATA---------------- //---------------DATA----------------
//-----------[data bytes]------------ //-----------[data bytes]------------
uint8_t *tmp_data_addr = (uint8_t *)modbus_msg->DATA; uint8_t *tmp_data_addr = (uint8_t *)modbus_msg->MbData;
for(int i = 0; i < modbus_msg->ByteCnt; i++) // filling buffer with data for(int i = 0; i < modbus_msg->ByteCnt; i++) // filling buffer with data
{ // set data { // set data
modbus_uart_buff[ind++] = *tmp_data_addr; modbus_uart_buff[ind++] = *tmp_data_addr;
@@ -209,18 +287,21 @@ RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeD
} }
} }
else if(modbus_msg->Func_Code == MB_R_DIAGNOSTIC) #endif //MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
#ifdef MODBUS_ENABLE_DIAGNOSTICS
else if(modbus_msg->FuncCode == FC_R_DIAGNOSTICS)
{ {
// Diagnostics special format: [SubFunc_HI][SubFunc_LO][Data_HI][Data_LO] // 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->MbData[0] >> 8; // Sub-function HI
modbus_uart_buff[ind++] = modbus_msg->DATA[0] & 0xFF; // Sub-function LO modbus_uart_buff[ind++] = modbus_msg->MbData[0] & 0xFF; // Sub-function LO
modbus_uart_buff[ind++] = modbus_msg->DATA[1] >> 8; // Data HI modbus_uart_buff[ind++] = modbus_msg->MbData[1] >> 8; // Data HI
modbus_uart_buff[ind++] = modbus_msg->DATA[1] & 0xFF; // Data LO modbus_uart_buff[ind++] = modbus_msg->MbData[1] & 0xFF; // Data LO
} }
#endif //MODBUS_ENABLE_DIAGNOSTICS
else // modbus data header else // modbus data header
{ {
// set size of received data // set size of received data
if (modbus_msg->ByteCnt <= DATA_SIZE*2) // if ByteCnt less than DATA_SIZE if (modbus_msg->ByteCnt <= MbData_size*2) // if ByteCnt less than MbData_size
modbus_uart_buff[ind++] = modbus_msg->ByteCnt; modbus_uart_buff[ind++] = modbus_msg->ByteCnt;
else // otherwise return data_size err else // otherwise return data_size err
{ {
@@ -230,7 +311,7 @@ RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeD
//---------------DATA---------------- //---------------DATA----------------
//-----------[data bytes]------------ //-----------[data bytes]------------
uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->DATA; uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->MbData;
for(int i = 0; i < modbus_msg->ByteCnt; i++) // filling buffer with data for(int i = 0; i < modbus_msg->ByteCnt; i++) // filling buffer with data
{ // set data { // set data
if (i%2 == 0) // HI byte if (i%2 == 0) // HI byte
@@ -255,12 +336,14 @@ RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeD
//---------------CRC---------------- //---------------CRC----------------
//---------[last 16 bytes]---------- //---------[last 16 bytes]----------
#ifndef MODBUS_PROTOCOL_TCP
// calc crc of received data // calc crc of received data
uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind); uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind);
// write crc to message structure and modbus-uart buffer // write crc to message structure and modbus-uart buffer
modbus_msg->MB_CRC = CRC_VALUE; modbus_msg->MbCRC = CRC_VALUE;
modbus_uart_buff[ind++] = CRC_VALUE; modbus_uart_buff[ind++] = CRC_VALUE;
modbus_uart_buff[ind++] = CRC_VALUE >> 8; modbus_uart_buff[ind++] = CRC_VALUE >> 8;
#endif
hmodbus->RS_Message_Size = ind; hmodbus->RS_Message_Size = ind;
@@ -279,15 +362,15 @@ static int MB_Define_Size_of_Function(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *
RS_StatusTypeDef MB_RES = 0; RS_StatusTypeDef MB_RES = 0;
int mb_func_size = 0; int mb_func_size = 0;
if (modbus_msg->Func_Code == MB_R_DIAGNOSTIC) if (modbus_msg->FuncCode == FC_R_DIAGNOSTICS)
{ {
mb_func_size = 1; mb_func_size = 1;
} }
else if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) else if(modbus_msg->FuncCode == FC_R_DEVICE_ID)
{ {
mb_func_size = 0; mb_func_size = 0;
} }
else if ((modbus_msg->Func_Code & ~ERR_VALUES_START) < 0x0F) else if ((modbus_msg->FuncCode & ~FC_ERR_VALUES_START) < 0x0F)
{ {
mb_func_size = 1; mb_func_size = 1;
} }
@@ -297,7 +380,7 @@ static int MB_Define_Size_of_Function(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *
} }
mb_func_size = RX_FIRST_PART_SIZE + mb_func_size; // size of whole message mb_func_size = RS_RX_FIRST_PART_SIZE + mb_func_size; // size of whole message
return mb_func_size; return mb_func_size;
} }
@@ -317,46 +400,61 @@ RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef
hmodbus->f.RX_Continue = 0; hmodbus->f.RX_Continue = 0;
int expected_size = 0; int expected_size = 0;
//-----INFO ABOUT DATA/MESSAGE------- //-----INFO ABOUT DATA/MESSAGE-------
#ifdef MODBUS_PROTOCOL_TCP
modbus_msg->TransactionID =modbus_uart_buff[ind++]<<8;
modbus_msg->TransactionID |=modbus_uart_buff[ind++];
modbus_msg->ProtocolID =modbus_uart_buff[ind++]<<8;
modbus_msg->ProtocolID |=modbus_uart_buff[ind++];
modbus_msg->PDULength =modbus_uart_buff[ind++]<<8;
modbus_msg->PDULength |=modbus_uart_buff[ind++];
#endif
//-----------[first bits]------------ //-----------[first bits]------------
// get ID of message/user // get ID of message/user
if(modbus_uart_buff[ind] != hmodbus->ID) if(modbus_uart_buff[ind] != hmodbus->ID)
{ {
modbus_msg->MbAddr = 0; modbus_msg->DeviceAddr = 0;
ind++; ind++;
} }
else else
{ {
modbus_msg->MbAddr = modbus_uart_buff[ind++]; modbus_msg->DeviceAddr = modbus_uart_buff[ind++];
} }
// get func code // get func code
modbus_msg->Func_Code = modbus_uart_buff[ind++]; modbus_msg->FuncCode = modbus_uart_buff[ind++];
if(modbus_msg->Func_Code & ERR_VALUES_START) // явная херня if(modbus_msg->FuncCode & FC_ERR_VALUES_START) // явная херня
{ {
MB_Diagnostics_SlaveNAKCnt(); MB_Diagnostics_SlaveNAKCnt();
modbus_msg->MbAddr = 0; modbus_msg->DeviceAddr = 0;
return RS_SKIP; return RS_SKIP;
} }
if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) // if it device identifications request if(0) {}
#ifdef MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
else if(modbus_msg->FuncCode == FC_R_DEVICE_ID) // if it device identifications request
{ {
modbus_msg->DevId.MEI_Type = modbus_uart_buff[ind++]; modbus_msg->DevId.MEI_Type = modbus_uart_buff[ind++];
modbus_msg->DevId.ReadDevId = modbus_uart_buff[ind++]; modbus_msg->DevId.ReadDevId = modbus_uart_buff[ind++];
modbus_msg->DevId.NextObjId = modbus_uart_buff[ind++]; modbus_msg->DevId.NextObjId = modbus_uart_buff[ind++];
modbus_msg->ByteCnt = 0; modbus_msg->ByteCnt = 0;
} }
else if(modbus_msg->Func_Code == MB_R_DIAGNOSTIC) #endif //MODBUS_ENABLE_DEVICE_IDENTIFICATIONS
#ifdef MODBUS_ENABLE_DIAGNOSTICS
else if(modbus_msg->FuncCode == FC_R_DIAGNOSTICS)
{ {
// Diagnostics: читаем 4 байта в DATA[0] и DATA[1] // Diagnostics: читаем 4 байта в MbData[0] и MbData[1]
// Sub-function // Sub-function
modbus_msg->DATA[0] = modbus_uart_buff[ind++] << 8; modbus_msg->MbData[0] = modbus_uart_buff[ind++] << 8;
modbus_msg->DATA[0] |= modbus_uart_buff[ind++]; modbus_msg->MbData[0] |= modbus_uart_buff[ind++];
// Data // Data
modbus_msg->DATA[1] = modbus_uart_buff[ind++] << 8; modbus_msg->MbData[1] = modbus_uart_buff[ind++] << 8;
modbus_msg->DATA[1] |= modbus_uart_buff[ind++]; modbus_msg->MbData[1] |= modbus_uart_buff[ind++];
modbus_msg->Addr = 0; // не использует Addr modbus_msg->Addr = 0; // не использует Addr
modbus_msg->Qnt = 0; // не использует Qnt modbus_msg->Qnt = 0; // не использует Qnt
} }
#endif //MODBUS_ENABLE_DIAGNOSTICS
else // if its classic modbus request else // if its classic modbus request
{ {
// get address from CMD // get address from CMD
@@ -368,7 +466,7 @@ RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef
modbus_msg->Qnt |= modbus_uart_buff[ind++]; modbus_msg->Qnt |= modbus_uart_buff[ind++];
} }
if((hmodbus->pMessagePtr->Func_Code == 0x0F) || (hmodbus->pMessagePtr->Func_Code == 0x10)) if((hmodbus->pMessagePtr->FuncCode == 0x0F) || (hmodbus->pMessagePtr->FuncCode == 0x10))
hmodbus->pMessagePtr->ByteCnt = modbus_uart_buff[ind++]; hmodbus->pMessagePtr->ByteCnt = modbus_uart_buff[ind++];
else else
hmodbus->pMessagePtr->ByteCnt = 0; hmodbus->pMessagePtr->ByteCnt = 0;
@@ -392,14 +490,14 @@ RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef
if (modbus_msg->ByteCnt != 0) if (modbus_msg->ByteCnt != 0)
{ {
//check that data size is correct //check that data size is correct
if (modbus_msg->ByteCnt > DATA_SIZE*2) if (modbus_msg->ByteCnt > MbData_size*2)
{ {
TrackerCnt_Err(hmodbus->rs_err); TrackerCnt_Err(hmodbus->rs_err);
modbus_msg->Func_Code |= ERR_VALUES_START; modbus_msg->FuncCode |= FC_ERR_VALUES_START;
MB_Diagnostics_CommunicationErrorCnt(); MB_Diagnostics_CommunicationErrorCnt();
return RS_PARSE_MSG_ERR; return RS_PARSE_MSG_ERR;
} }
uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->DATA; uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->MbData;
for(int i = 0; i < modbus_msg->ByteCnt; i++) for(int i = 0; i < modbus_msg->ByteCnt; i++)
{ // set data { // set data
if (i%2 == 0) if (i%2 == 0)
@@ -414,24 +512,22 @@ RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef
//---------------CRC---------------- //---------------CRC----------------
//----------[last 16 bits]---------- //----------[last 16 bits]----------
#ifndef MODBUS_PROTOCOL_TCP
// calc crc of received data // calc crc of received data
uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind); uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind);
// get crc of received data // get crc of received data
modbus_msg->MB_CRC = modbus_uart_buff[ind++]; modbus_msg->MbCRC = modbus_uart_buff[ind++];
modbus_msg->MB_CRC |= modbus_uart_buff[ind++] << 8; modbus_msg->MbCRC |= modbus_uart_buff[ind++] << 8;
// compare crc // compare crc
if (modbus_msg->MB_CRC != CRC_VALUE) if (modbus_msg->MbCRC != CRC_VALUE)
{ {
MB_Diagnostics_CommunicationErrorCnt(); MB_Diagnostics_CommunicationErrorCnt();
TrackerCnt_Err(hmodbus->rs_err); TrackerCnt_Err(hmodbus->rs_err);
modbus_msg->Func_Code |= ERR_VALUES_START; modbus_msg->FuncCode |= FC_ERR_VALUES_START;
} }
#endif
return RS_OK; return RS_OK;
} }
#else // MODBUS_ENABLE_SLAVE #endif //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

View File

@@ -1,8 +1,8 @@
/** /**
****************************************************************************** *******************************************************************************
* @file rs_message.c * @file rs_message.c
* @brief Реализация протоколов обмена по RS/UART * @brief Реализация протоколов обмена по RS/UART
****************************************************************************** *******************************************************************************
* @details * @details
Модуль реализует асинхронный обмен сообщениями через UART с использованием: Модуль реализует асинхронный обмен сообщениями через UART с использованием:
- Прерываний по приему/передаче - Прерываний по приему/передаче
@@ -10,23 +10,21 @@
- Таймаутов через таймер - Таймаутов через таймер
- Двухстадийного приема (заголовок + данные) - Двухстадийного приема (заголовок + данные)
@section Архитектура: @section arch Архитектура:
В режиме слейв: В режиме слейв:
- Инициализация приема с сообщения с максимальным размером MSG_SIZE_MAX - Инициализация приема с сообщения с максимальным размером RS_MSG_SIZE_MAX
- При срабатывании прерывания IDLE - обработка полученного сообщения - При срабатывании прерывания IDLE - обработка полученного сообщения
В режиме мастер (пока не реализовано): В режиме мастер (пока не реализовано):
- Отправка запроса и переход в режим приема сообщения с максимальным размером MSG_SIZE_MAX - Отправка запроса и переход в режим приема сообщения с максимальным размером RS_MSG_SIZE_MAX
- При срабатывании прерывания IDLE - обработка полученного ответа - При срабатывании прерывания IDLE - обработка полученного ответа
@section Необходимые обработчики: @section ithandler Необходимые обработчики:
- 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" #include "modbus_diag.h"
uint8_t RS_Buffer[MSG_SIZE_MAX]; // uart buffer
extern void RS_UART_Init(void); extern void RS_UART_Init(void);
extern void RS_UART_DeInit(UART_HandleTypeDef *huart); extern void RS_UART_DeInit(UART_HandleTypeDef *huart);
extern void RS_TIM_Init(void); extern void RS_TIM_Init(void);
@@ -52,7 +50,8 @@ RS_StatusTypeDef RS_Receive_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
//-----------INITIALIZE RECEIVE------------- //-----------INITIALIZE RECEIVE-------------
// if all OK: start receiving // if all OK: start receiving
RS_EnableReceive(); if(hRS->pSetDirection)
hRS->pSetDirection(0);
RS_Set_Busy(hRS); // set RS busy RS_Set_Busy(hRS); // set RS busy
RS_Set_RX_Flags(hRS); // initialize flags for receive RS_Set_RX_Flags(hRS); // initialize flags for receive
hRS->pMessagePtr = RS_msg; // set pointer to message structire for filling it from UARTHandler fucntions hRS->pMessagePtr = RS_msg; // set pointer to message structire for filling it from UARTHandler fucntions
@@ -61,7 +60,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->BufferPtr[hRS->RS_Message_Size], RS_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
@@ -101,7 +100,7 @@ RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
//------------COLLECT MESSAGE--------------- //------------COLLECT MESSAGE---------------
RS_RES = RS_Collect_Message(hRS, RS_msg, hRS->pBufferPtr); RS_RES = RS_Collect_Message(hRS, RS_msg, hRS->BufferPtr);
if (RS_RES != RS_OK) // if message isnt collect - stop RS and return error in RS_RES if (RS_RES != RS_OK) // if message isnt collect - stop RS and return error in RS_RES
{// need collect message status, so doesnt write abort to RS_RES {// need collect message status, so doesnt write abort to RS_RES
RS_Abort(hRS, ABORT_RS); RS_Abort(hRS, ABORT_RS);
@@ -111,7 +110,8 @@ RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
{ {
//----------INITIALIZE TRANSMIT------------- //----------INITIALIZE TRANSMIT-------------
RS_EnableTransmit(); if(hRS->pSetDirection)
hRS->pSetDirection(1);
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
@@ -123,7 +123,7 @@ RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
return RS_ERR; return RS_ERR;
} }
// if all OK: start transmitting // if all OK: start transmitting
uart_res = HAL_UART_Transmit_IT(hRS->huart, hRS->pBufferPtr, hRS->RS_Message_Size); uart_res = HAL_UART_Transmit_IT(hRS->huart, hRS->BufferPtr, hRS->RS_Message_Size);
// if transmit isnt started - abort RS // if transmit isnt started - abort RS
if(uart_res != HAL_OK) if(uart_res != HAL_OK)
{ {
@@ -153,7 +153,7 @@ RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg)
* @return RS_RES Статус о состоянии RS после инициализации. * @return RS_RES Статус о состоянии RS после инициализации.
* @details Инициализация перефирии и структуры для приема-передачи по 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, void (*pSetDirection)(int Tx))
{ {
// check that hRS is defined // check that hRS is defined
if (hRS == NULL) if (hRS == NULL)
@@ -166,13 +166,7 @@ RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_H
hRS->htim = htim; hRS->htim = htim;
// check that buffer is defined hRS->pSetDirection = pSetDirection;
if (hRS->pBufferPtr == NULL)
{
hRS->pBufferPtr = RS_Buffer; // if no - set default
}
else
hRS->pBufferPtr = pRS_BufferPtr; // if yes - set by user
return RS_OK; return RS_OK;
} }
@@ -323,6 +317,7 @@ void RS_UART_Handler(RS_HandleTypeDef *hRS)
{ {
return; return;
} }
RS_UART_Handler_ENTER();
//-------------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))
@@ -348,22 +343,24 @@ void RS_UART_Handler(RS_HandleTypeDef *hRS)
RS_Set_RX_End(hRS); RS_Set_RX_End(hRS);
// Парсим наше сообщение // Парсим наше сообщение
RS_StatusTypeDef parse_res = RS_Parse_Message(hRS, hRS->pMessagePtr, hRS->pBufferPtr); hRS->RS_STATUS = RS_Parse_Message(hRS, hRS->pMessagePtr, hRS->BufferPtr);
// Если сообещине принято корректно // Если сообещине принято корректно
if(parse_res == RS_OK) if(hRS->RS_STATUS == RS_OK)
{ {
RS_Timeout_Stop(hRS); RS_Timeout_Stop(hRS);
hRS->lastPacketTick = uwTick; hRS->lastPacketTick = local_time();
if(hRS->sRS_Mode < RS_MASTER_MODE_START) if(hRS->sRS_Mode < RS_MASTER_MODE_START)
{
RS_Response(hRS, hRS->pMessagePtr); // отвечаем на запрос RS_Response(hRS, hRS->pMessagePtr); // отвечаем на запрос
}
else else
{ {
RS_Set_Free(hRS); // освобожднаем RS
if(hRS->pCallback) if(hRS->pCallback)
{ {
hRS->pCallback(hRS, hRS->pMessagePtr); // обрабатываем ответ hRS->pCallback(hRS, hRS->pMessagePtr); // обрабатываем ответ
RS_Set_Free(hRS); // освобожднаем RS
} }
} }
} }
@@ -417,6 +414,7 @@ void RS_UART_Handler(RS_HandleTypeDef *hRS)
// later, maybe, will be added specific handlers for err // later, maybe, will be added specific handlers for err
} }
RS_UART_Handler_EXIT();
} }
@@ -432,20 +430,30 @@ void RS_TIM_Handler(RS_HandleTypeDef *hRS)
{ {
return; return;
} }
RS_TIM_Handler_ENTER();
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) // ошибка если таймаут по нашему сообщению hRS->RS_STATUS = RS_TIMEOUT;
if(hRS->sRS_Mode < RS_MASTER_MODE_START)
if(hRS->pMessagePtr->DeviceAddr == hRS->ID) // ошибка если таймаут по нашему сообщению
TrackerCnt_Err(hRS->rs_err); TrackerCnt_Err(hRS->rs_err);
if(hRS->sRS_Mode == RS_MASTER_REQUEST) { if(hRS->sRS_Mode >= RS_MASTER_MODE_START)
// Мастер: таймаут ответа -> освобождаем для нового запроса { // Мастер: коллбек и освобождение для нового запроса
RS_Set_Free(hRS); RS_Set_Free(hRS);
if(hRS->pCallback)
{
hRS->pCallback(hRS, hRS->pMessagePtr); // обрабатываем ответ
}
} else { } else {
// Слейв: перезапускаем прием // Слейв: перезапускаем прием
RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); RS_Handle_Receive_Start(hRS, hRS->pMessagePtr);
} }
RS_TIM_Handler_EXIT();
} }
/** /**

View File

@@ -5,13 +5,16 @@
****************************************************************************** ******************************************************************************
@addtogroup MODBUS_CONFIGS Modbus configs @addtogroup MODBUS_CONFIGS Modbus configs
@ingroup MODBUS @ingroup MODBUS
@brief Конфигурация библиотеки
@{ @{
****************************************************************************** ******************************************************************************
* @details * @details
Файл содержит настройки для работы Modbus: Файл содержит настройки для работы Modbus:
- Идентификатор устройства и таймауты - Подключение библиотек контроллера
- ID устройства и таймауты
- Строковые идентификаторы (Vendor, Product, Revision) - Строковые идентификаторы (Vendor, Product, Revision)
- Настройки периферии (UART, TIMER) - Настройки периферии (UART, TIMER)
- Подключение модулей Modbus
- Опциональные функции (переключение команд 0x03/0x04) - Опциональные функции (переключение команд 0x03/0x04)
******************************************************************************/ ******************************************************************************/
#ifndef _MODBUS_CONFIG_H_ #ifndef _MODBUS_CONFIG_H_
@@ -30,13 +33,13 @@
#define MODBUS_PRODUCT_NAME "" #define MODBUS_PRODUCT_NAME ""
#define MODBUS_MODEL_NAME "" #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 MODBUS_USEROBJECT_0_NAME "" ///< Строка пользовательского идентификатора 0. По аналогии можно определить строки до <=128 USEROBJECT
// Периферия (опционально) // Периферия (опционально)
#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 // Модули modbus
@@ -50,8 +53,11 @@
#define MODBUS_ENABLE_DIAGNOSTICS ///< Включить обработку диагностики модбас #define MODBUS_ENABLE_DIAGNOSTICS ///< Включить обработку диагностики модбас
#define MODBUS_ENABLE_OSCIL ///< Включить осциллограф Modbus
//#define MODBUS_PROTOCOL_TCP ///< Включить TCP-протокол, иначе - RTU
/** /**
* @brief Поменять комманды 0x03 и 0x04 местами (для LabView терминалки от двигателей) * @brief Поменять комманды 0x03 и 0x04 местами
* @details Терминалка от двигателей использует для чтения регистров комманду R_HOLD_REGS вместо R_IN_REGS * @details Терминалка от двигателей использует для чтения регистров комманду R_HOLD_REGS вместо R_IN_REGS
* Поэтому чтобы считывать Input Regs - надо поменять их местами. * Поэтому чтобы считывать Input Regs - надо поменять их местами.
*/ */

View File

@@ -22,6 +22,8 @@
#include "modbus_inputregs.h" #include "modbus_inputregs.h"
#include "modbus_devid.h" #include "modbus_devid.h"
/* DEFINE DATA FOR MODBUS */
MB_DataStructureTypeDef MB_DATA = { 0 }; ///< Coils & Registers
/** /**
* @brief Check is address valid for certain array. * @brief Check is address valid for certain array.
@@ -29,11 +31,11 @@
* @param Qnt Количество запрашиваемых элементов. * @param Qnt Количество запрашиваемых элементов.
* @param R_ARR_ADDR Начальный адресс массива R_ARR. * @param R_ARR_ADDR Начальный адресс массива R_ARR.
* @param R_ARR_NUMB Количество элементов в массиве R_ARR. * @param R_ARR_NUMB Количество элементов в массиве R_ARR.
* @return ExceptionCode - ILLEGAL DATA ADRESS если адресс недействителен, и NO_ERRORS если все ок. * @return ExceptionCode - ET_ILLEGAL_DATA_ADRESS если адресс недействителен, и ET_NO_ERRORS если все ок.
* *
* @details Позволяет определить, принадлежит ли адресс Addr массиву R_ARR: * @details Позволяет определить, принадлежит ли адресс Addr массиву R_ARR:
* Если адресс Addr находится в диапазоне адрессов массива R_ARR, то возвращаем NO_ERROR. * Если адресс Addr находится в диапазоне адрессов массива R_ARR, то возвращаем NO_ERROR.
* Если адресс Addr находится за пределами адрессов массива R_ARR - ILLEGAL_DATA_ADDRESSю. * Если адресс Addr находится за пределами адрессов массива R_ARR - ET_ILLEGAL_DATA_ADDRESSю.
*/ */
MB_ExceptionTypeDef MB_Check_Address_For_Arr(uint16_t Addr, uint16_t Qnt, uint16_t R_ARR_ADDR, uint16_t R_ARR_NUMB) MB_ExceptionTypeDef MB_Check_Address_For_Arr(uint16_t Addr, uint16_t Qnt, uint16_t R_ARR_ADDR, uint16_t R_ARR_NUMB)
{ {
@@ -43,14 +45,14 @@ MB_ExceptionTypeDef MB_Check_Address_For_Arr(uint16_t Addr, uint16_t Qnt, uint16
// if quantity too big return error // if quantity too big return error
if ((Addr - R_ARR_ADDR) + Qnt > R_ARR_NUMB) if ((Addr - R_ARR_ADDR) + Qnt > R_ARR_NUMB)
{ {
return ILLEGAL_DATA_ADDRESS; // return exception code return ET_ILLEGAL_DATA_ADDRESS; // return exception code
} }
// if all ok - return no errors // if all ok - return no errors
return NO_ERRORS; return ET_NO_ERRORS;
} }
// if address isnt from this array return error // if address isnt from this array return error
else else
return ILLEGAL_DATA_ADDRESS; // return exception code return ET_ILLEGAL_DATA_ADDRESS; // return exception code
} }
/** /**
* @brief Define Address Origin for Input/Holding Registers * @brief Define Address Origin for Input/Holding Registers
@@ -58,51 +60,58 @@ MB_ExceptionTypeDef MB_Check_Address_For_Arr(uint16_t Addr, uint16_t Qnt, uint16
* @param Addr Адрес начального регистра. * @param Addr Адрес начального регистра.
* @param Qnt Количество запрашиваемых регистров. * @param Qnt Количество запрашиваемых регистров.
* @param WriteFlag Флаг регистр нужны для чтения или записи. * @param WriteFlag Флаг регистр нужны для чтения или записи.
* @return ExceptionCode Код исключения если есть, и NO_ERRORS если нет. * @return ExceptionCode Код исключения если есть, и ET_NO_ERRORS если нет.
* *
* @details Определение адреса начального регистра. * @details Определение адреса начального регистра.
* @note WriteFlag пока не используется. * @note WriteFlag пока не используется.
*/ */
MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, uint16_t Qnt, uint8_t RegisterType) MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, uint16_t Qnt, uint8_t RegisterType, uint8_t WriteFlag)
{ {
/* check quantity error */ /* check quantity error */
if (Qnt > DATA_SIZE) if (Qnt > MbData_size)
{ {
return ILLEGAL_DATA_VALUE; // return exception code return ET_ILLEGAL_DATA_VALUE; // return exception code
} }
if(RegisterType == RegisterType_Holding) if(RegisterType == RegisterType_Holding)
{ {
// 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) == ET_NO_ERRORS)
{ {
*pRegs = MB_Set_Register_Ptr(&MB_DATA.HoldRegs, Addr - R_HOLDING_ADDR); // указатель на выбранный по Addr регистр *pRegs = MB_Set_Register_Ptr(&MB_DATA.HoldRegs, Addr - R_HOLDING_ADDR); // указатель на выбранный по Addr регистр
} }
#if defined(MODBUS_ENABLE_OSCIL) && defined(R_HOLDING_OSCIL_ADDR) && defined(R_HOLDING_OSCIL_QNT)
else if(MB_Check_Address_For_Arr(Addr, Qnt, R_HOLDING_OSCIL_ADDR, R_HOLDING_OSCIL_QNT) == ET_NO_ERRORS)
{
local_addr = Addr - R_HOLDING_OSCIL_ADDR;
*pRegs = MB_Set_Register_Ptr(&MB_INTERNAL.oscil , local_addr); // указатель на выбранный по Addr регистр
}
#endif
// if address doesnt match any array - return illegal data address response // if address doesnt match any array - return illegal data address response
else else
{ {
return ILLEGAL_DATA_ADDRESS; return ET_ILLEGAL_DATA_ADDRESS;
} }
} }
else if(RegisterType == RegisterType_Input) else if(RegisterType == RegisterType_Input)
{ {
// 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) == ET_NO_ERRORS)
{ {
*pRegs = MB_Set_Register_Ptr(&MB_DATA.InRegs, Addr - R_INPUT_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
{ {
return ILLEGAL_DATA_ADDRESS; return ET_ILLEGAL_DATA_ADDRESS;
} }
} }
else else
{ {
return ILLEGAL_FUNCTION; return ET_ILLEGAL_FUNCTION;
} }
// if found requeried array return no err // if found requeried array return no err
return NO_ERRORS; // return no errors return ET_NO_ERRORS; // return no errors
} }
/** /**
* @brief Define Address Origin for coils * @brief Define Address Origin for coils
@@ -111,7 +120,7 @@ MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, u
* @param Qnt Количество запрашиваемых коилов. * @param Qnt Количество запрашиваемых коилов.
* @param start_shift Указатель на переменную содержащую сдвиг внутри регистра для начального коила. * @param start_shift Указатель на переменную содержащую сдвиг внутри регистра для начального коила.
* @param WriteFlag Флаг коилы нужны для чтения или записи. * @param WriteFlag Флаг коилы нужны для чтения или записи.
* @return ExceptionCode Код исключения если есть, и NO_ERRORS если нет. * @return ExceptionCode Код исключения если есть, и ET_NO_ERRORS если нет.
* *
* @details Определение адреса начального регистра запрашиваемых коилов. * @details Определение адреса начального регистра запрашиваемых коилов.
* @note WriteFlag используется для определния регистров GPIO: ODR или IDR. * @note WriteFlag используется для определния регистров GPIO: ODR или IDR.
@@ -121,21 +130,21 @@ MB_ExceptionTypeDef MB_DefineCoilsAddress(uint16_t **pCoils, uint16_t Addr, uint
/* check quantity error */ /* check quantity error */
if (Qnt > 2000) if (Qnt > 2000)
{ {
return ILLEGAL_DATA_VALUE; // return exception code return ET_ILLEGAL_DATA_VALUE; // return exception code
} }
// 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) == ET_NO_ERRORS)
{ {
*pCoils = MB_Set_Coil_Reg_Ptr(&MB_DATA.Coils, Addr - C_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
{ {
return ILLEGAL_DATA_ADDRESS; return ET_ILLEGAL_DATA_ADDRESS;
} }
*start_shift = Addr % 16; // set shift to requested coil *start_shift = Addr % 16; // set shift to requested coil
// if found requeried array return no err // if found requeried array return no err
return NO_ERRORS; // return no errors return ET_NO_ERRORS; // return no errors
} }

View File

@@ -3,7 +3,7 @@
* @file modbus_data.h * @file modbus_data.h
* @brief Определения структур данных Modbus устройства * @brief Определения структур данных Modbus устройства
****************************************************************************** ******************************************************************************
@defgroup MODBUS_DATA Modbus Data Tools @defgroup MODBUS_DATA Modbus Registers Map
@ingroup MODBUS @ingroup MODBUS
@brief Определение карты регистров и коилов @brief Определение карты регистров и коилов
****************************************************************************** ******************************************************************************
@@ -13,7 +13,7 @@
- Input Registers (R/O) - входные регистры - Input Registers (R/O) - входные регистры
- Coils (R/W) - дискретные выходы - Coils (R/W) - дискретные выходы
@section Базовая настройка под устройство: @section datinit Базовая настройка под устройство:
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 datexpert Расширенная настройка под устройство:
1. Добавить новый массив с нужными данными. 1. Добавить новый массив с нужными данными.
2. Добавить дефайны для определения его начального адреса и количества элементов 2. Добавить дефайны для определения его начального адреса и количества элементов
3. Добавить проверку адресов в MB_DefineRegistersAddress/MB_DefineCoilsAddress. 3. Добавить проверку адресов в MB_DefineRegistersAddress/MB_DefineCoilsAddress.
@@ -36,14 +36,14 @@
uint16_t user_regs[16]; uint16_t user_regs[16];
//... //...
else if(MB_Check_Address_For_Arr(Addr, Qnt, R_USER_ADDR, R_USER_QNT) == NO_ERRORS) else if(MB_Check_Address_For_Arr(Addr, Qnt, R_USER_ADDR, R_USER_QNT) == ET_NO_ERRORS)
{ {
*pRegs = MB_Set_Register_Ptr(&user_regs, Addr-R_USER_ADDR); // ВАЖНО! *pRegs = MB_Set_Register_Ptr(&user_regs, Addr-R_USER_ADDR); // ВАЖНО!
// -R_USER_ADDR нужен чтобы взять адрес относительно начала массива // -R_USER_ADDR нужен чтобы взять адрес относительно начала массива
} }
else else
{ {
return ILLEGAL_DATA_ADDRESS; return ET_ILLEGAL_DATA_ADDRESS;
} }
@endcode @endcode
******************************************************************************/ ******************************************************************************/
@@ -75,11 +75,11 @@
* @addtogroup MODBUS_DATA_RERISTERS_DEFINES Registers structures * @addtogroup MODBUS_DATA_RERISTERS_DEFINES Registers structures
* @ingroup MODBUS_DATA * @ingroup MODBUS_DATA
* @brief Стуруктура регистров (входных и хранения) * @brief Стуруктура регистров (входных и хранения)
@verbatim @code
Для массивов регистров: Для массивов регистров:
R_<NAME_ARRAY>_ADDR - модбас адресс первого регистра в массиве R_<NAME_ARRAY>_ADDR - модбас адресс первого регистра в массиве
R_<NAME_ARRAY>_QNT - количество регистров в массиве R_<NAME_ARRAY>_QNT - количество регистров в массиве
@endverbatim @endcode
* @{ * @{
*/ */
@@ -111,12 +111,12 @@ typedef struct //MB_DataInRegsTypeDef
* @addtogroup MODBUS_DATA_COILS_DEFINES Coils Structure * @addtogroup MODBUS_DATA_COILS_DEFINES Coils Structure
* @ingroup MODBUS_DATA * @ingroup MODBUS_DATA
* @brief Структура коилов * @brief Структура коилов
@verbatim @code
Структура дефайна Структура дефайна
Для массивов коилов: Для массивов коилов:
C_<NAME_ARRAY>_ADDR - модбас адресс первого коила в массиве C_<NAME_ARRAY>_ADDR - модбас адресс первого коила в массиве
C_<NAME_ARRAY>_QNT - количество коилов в массиве (минимум 16) C_<NAME_ARRAY>_QNT - количество коилов в массиве (минимум 16)
@endverbatim @endcode
* @{ * @{
*/ */