pre-release 0.1

проверка
This commit is contained in:
2025-11-03 19:50:46 +03:00
parent 7e21fc7f28
commit dfadef7b43
944 changed files with 162 additions and 585750 deletions

9
Inc/__crc_algs.h Normal file
View File

@@ -0,0 +1,9 @@
#include "modbus_config.h"
// extern here to use in bootloader.c
extern uint32_t CRC_calc;
extern uint32_t CRC_ref;
uint16_t crc16(uint8_t *data, uint32_t data_size);
uint32_t crc32(uint8_t *data, uint32_t data_size);

101
Inc/modbus.h Normal file
View File

@@ -0,0 +1,101 @@
/**
******************************************************************************
* @file modbus.h
* @brief Главный заголовочный файл Modbus библиотеки
******************************************************************************
@addtogroup MODBUS Modbus tools
******************************************************************************
@addtogroup MODBUS_FUNCTIONS Modbus library funtions
@ingroup MODBUS
@{
******************************************************************************
* @details
Объединяющий файл для подключения всей функциональности Modbus.
Подключает все необходимые модули:
@section Инструкция по подключению
Для корректной работы надо:
- Подключить обработчики RS_UART_Handler(), RS_TIM_Handler(), в соответствубщие
низкоуровневые прерывания UART_IRQHandler, TIM_IRQHandler. Вместо HAL'овского обработчика
В modbus_config.h настроить дефайны для нужной работы UART
- Инициализировать хендл мобдас. По умолчанию глобально создается hmodbus1, но можно сделать свой
После для запуска Modbus:
@verbatim
//----------------Прием модбас----------------//
#include "modbus.h"
MODBUS_SetupHardware(&hmodbus1, &huart1, &htim3);
MODBUS_SlaveStart(&hmodbus1, NULL);
// или если нужно переключится на другой
@endverbatim
@section Подключаемые модули:
- modbus_core.h - базовые определения
- modbus_coils.h - работа с дискретными выходами
- modbus_holdregs.h - работа с регистрами хранения
- modbus_inputregs.h - работа с входными регистрами
- modbus_devid.h - идентификация устройства
- __crc_algs.h - алгоритмы CRC
@section Использование в проекте:
1. Настроить modbus_config.h под устройство
2. Определить структуры данных в modbus_data.h
3. Подключить этот файл в rs_message.h
4. Вызвать MODBUS_FirstInit() и RS_Receive_IT()
@section Структура данных Modbus
#### Holding/Input Registers:
- Регистры — 16-битные слова. Доступ к регистрам осуществляется через указатель.
Таким образом, сами регистры могут представлять собой как массив так и структуру.
#### Coils:
- Coils — это биты, упакованные в 16-битные слова. Доступ к коилам осуществляется через указатель.
Таким образом, сами коилы могут представлять собой как массив так и структуру.
******************************************************************************/
#ifndef __MODBUS_H_
#define __MODBUS_H_
#include "__crc_algs.h"
#include "rs_message.h"
#include "modbus_coils.h"
#include "modbus_holdregs.h"
#include "modbus_inputregs.h"
#include "modbus_devid.h"
/////////////////////////////////////////////////////////////////////
/////////////////////////---FUNCTIONS---/////////////////////////////
//----------------FUNCTIONS FOR USER----------------
/**
* @addtogroup MODBUS_INIT_FUNCTIONS Functions for Init
* @ingroup MODBUS_FUNCTIONS
* @brief Функции для инициализации
@{
*/
/* Инициализация периферии модбас. */
void MODBUS_SetupHardware(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim);
/* Программная конфигурация модбас. */
void MODBUS_Config(RS_HandleTypeDef *hmodbus, uint8_t ID, uint16_t Timeout, uint8_t master);
/** MODBUS_INIT_FUNCTIONS
* @}
*/
//---------PROCESS MODBUS COMMAND FUNCTIONS---------
/////////////////////////---FUNCTIONS---/////////////////////////////
#endif //__MODBUS_H_
/** MODBUS_FUNCTIONS
* @}
*/

152
Inc/modbus_coils.h Normal file
View File

@@ -0,0 +1,152 @@
/**
******************************************************************************
* @file modbus_coils.h
* @brief Работа с коилами Modbus
******************************************************************************
@addtogroup MODBUS_COILS Coils Tools
@ingroup MODBUS_INTERNAL
@{
******************************************************************************
* @details
Модуль предоставляет функции и макросы для работы с битовыми данными:
- Чтение coils (0x01) Упаковка битов в байты
- Запись одиночного coil (0x05) Установка/сброс бита
- Запись множественных coils (0x0F) - распаковка байтов в биты
- Макросы для локального доступа к coils
@section Организация битовых данных:
Coils упакованы в 16-битные слова для эффективного использования памяти.
Биты нумеруются от младшего к старшему внутри каждого слова.
@section Адресация:
- Глобальная - абсолютный адрес в пространстве Modbus
- Локальная - относительный адрес внутри массива coils
- Макросы автоматически вычисляют смещения и маски
******************************************************************************/
#ifndef __MODBUS_COILS_H_
#define __MODBUS_COILS_H_
#include "modbus_core.h"
/////////////////////////////////////////////////////////////////////
////////////////////---MODBUS FUNCTION DEFINES---////////////////////
/** @brief Structure for coils operation */
typedef enum
{
SET_COIL,
RESET_COIL,
TOOGLE_COIL,
}MB_CoilsOpTypeDef;
//--------------------------------------------------
/**
* @brief Macros to set pointer to a certain register that contains certain coil
* @param _parr_ - массив коилов.
* @param _coil_ - Номер коила от начала массива _arr_.
* @note Используется вместе с @ref MB_Set_Coil_Mask
@verbatim Пояснение выражений
(_coil_/16) - get index (address shift) of register that contain certain coil
Visual explanation: 30th coil in coils registers array
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 Macros to set mask to a certain bit in coils register
* @param _coil_ - Номер коила от начала массива _arr_.
* @note Используется вместе с @ref MB_Set_Coil_Reg_Ptr
@verbatim Пояснение выражений
(16*(_coil_/16) - how many coils we need to skip. e.g. (16*30/16) - skip 16 coils from first register
_coil_-(16*(_coil_/16)) - shift to certain coil in certain register
e.g. Coil(30) gets in register[1] (30/16 = 1) coil №14 (30 - (16*30/16) = 30 - 16 = 14)
Visual explanation: 30th coil in coils registers array
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)) ))
/////////////////////////////////////////////////////////////////////
/////////////////////////---FUNCTIONS---/////////////////////////////
/**
* @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS Modbus Data Access
* @ingroup MODBUS_FUNCTIONS
* @brief Функции для доступа к данным модбас (коилы)
@{
*/
/**
* @brief Read Coil at its local address.
* @param _parr_ - массив коилов.
* @param _coil_ - Номер коила от начала массива _arr_.
* @return uint16_t Возвращает запрошенный коил на 0м бите.
*
* @details Позволяет обратиться к коилу по адресу относительно _arr_.
*/
#define MB_Read_Coil_Local(_parr_, _coil_) (( *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) & MB_Set_Coil_Mask(_coil_) ) >> (_coil_))
/**
* @brief Set Coil at its local address.
* @param _parr_ Указатель на массив коилов.
* @param _coil_ - Номер коила от начала массива _arr_.
*
* @details Позволяет обратиться к коилу по адресу относительно _arr_.
*/
#define MB_Set_Coil_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) |= MB_Set_Coil_Mask(_coil_)
/**
* @brief Reset Coil at its local address.
* @param _parr_ Указатель на массив коилов.
* @param _coil_ - Номер коила от начала массива _arr_.
*
* @details Позволяет обратиться к коилу по адресу относительно _arr_.
*/
#define MB_Reset_Coil_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) &= ~(MB_Set_Coil_Mask(_coil_))
/**
* @brief Set Coil at its local address.
* @param _parr_ Указатель на массив коилов.
* @param _coil_ - Номер коила от начала массива _arr_.
*
* @details Позволяет обратиться к коилу по адресу относительно _arr_.
*/
#define MB_Toogle_Coil_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) ^= MB_Set_Coil_Mask(_coil_)
/* Set or Reset Coil at its global address */
MB_ExceptionTypeDef MB_Write_Coil_Global(uint16_t Addr, MB_CoilsOpTypeDef WriteVal);
/* Read Coil at its global address */
uint16_t MB_Read_Coil_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception);
/** MODBUS_DATA_ACCESS_FUNCTIONS
* @}
*/
//---------PROCESS MODBUS COMMAND FUNCTIONS---------
/**
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
@{
*/
/* Proccess command Read Coils (01 - 0x01) */
uint8_t MB_Proccess_Read_Coils(RS_MsgTypeDef *modbus_msg);
/* Proccess command Write Single Coils (05 - 0x05) */
uint8_t MB_Proccess_Write_Single_Coil(RS_MsgTypeDef *modbus_msg);
/* Proccess command Write Multiple Coils (15 - 0x0F) */
uint8_t MB_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg);
/** MODBUS_CMD_PROCESS_FUNCTIONS
* @}
*/
/////////////////////////---FUNCTIONS---/////////////////////////////
#endif //__MODBUS_COILS_H_
/** MODBUS_COILS
* @}
*/

256
Inc/modbus_core.h Normal file
View File

@@ -0,0 +1,256 @@
/**
******************************************************************************
* @file modbus_core.h
* @brief Ядро Modbus протокола - определения и структуры
******************************************************************************
@addtogroup MODBUS_INTERNAL Modbus Internal Tools
@ingroup MODBUS
@{
******************************************************************************
* @details
Базовые определения для реализации Modbus RTU устройства:
- Структуры сообщений Modbus
Коды функций и исключений
Константы размеров полей
Вспомогательные макросы
@section Структура сообщения:
[ADDR][FUNC][DATA...][CRC]
- Адрес: 1 байт
- Функция: 1 байт
- Данные: переменной длины
- CRC: 2 байта
******************************************************************************/
#ifndef __MODBUS_CORE_H_
#define __MODBUS_CORE_H_
#include "modbus_config.h"
#include "modbus_data.h"
/**
* @addtogroup MODBUS_MESSAGE_DEFINES Modbus Message Tools
* @ingroup MODBUS
* @brief Определения протокола модбас
@{
*/
/////////////////////////////////////////////////////////////////////
////////////////////---MODBUS MESSAGE DEFINES---/////////////////////
//-------------DEFINES FOR STRUCTURE----------------
/* defines for structure of modbus message */
#define MbAddr_SIZE 1 ///< size of (MbAddr)
#define Func_Code_SIZE 1 ///< size of (Func_Code)
#define Addr_SIZE 2 ///< size of (Addr)
#define Qnt_SIZE 2 ///< size of (Qnt)
#define ByteCnt_SIZE 1 ///< size of (ByteCnt)
#define DATA_SIZE 125 ///< maximum number of data: DWORD (NOT MESSAGE SIZE)
#define CRC_SIZE 2 ///< size of (MB_CRC) in bytes
/** @brief Size of whole message */
#define INFO_SIZE_MAX (MbAddr_SIZE+Func_Code_SIZE+Addr_SIZE+Qnt_SIZE+ByteCnt_SIZE)
/** @brief Size of first part of message that will be received
first receive info part of message, than defines size of rest message*/
#define RX_FIRST_PART_SIZE INFO_SIZE_MAX
/** @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
/** @brief Structure for modbus exception codes */
typedef enum //MB_ExceptionTypeDef
{
// reading
NO_ERRORS = 0x00, ///< no errors
ILLEGAL_FUNCTION = 0x01, ///< Принятый код функции не может быть обработан
ILLEGAL_DATA_ADDRESS = 0x02, ///< Адрес данных, указанный в запросе, недоступен
ILLEGAL_DATA_VALUE = 0x03, ///< Значение, содержащееся в поле данных запроса, является недопустимой величиной
SLAVE_DEVICE_FAILURE = 0x04, ///< Невосстанавливаемая ошибка имела место, пока ведомое устройство пыталось выполнить затребованное действие
// ACKNOWLEDGE = 0x05, ///< idk
// SLAVE_DEVICE_BUSY = 0x06, ///< idk
// MEMORY_PARITY_ERROR = 0x08, ///< idk
}MB_ExceptionTypeDef;
#define ERR_VALUES_START 0x80U ///< from this value starts error func codes
/** @brief Structure for modbus func codes */
typedef enum //MB_FunctonTypeDef
{
/* COMMANDS */
// reading
MB_R_COILS = 0x01, ///< Чтение битовых ячеек
MB_R_DISC_IN = 0x02, ///< Чтение дискретных входов
#ifndef MODBUS_SWITCH_COMMAND_R_IN_REGS_AND_R_HOLD_REGS
MB_R_HOLD_REGS = 0x03, ///< Чтение входных регистров
MB_R_IN_REGS = 0x04, ///< Чтение регистров хранения
#else
MB_R_HOLD_REGS = 0x04, ///< Чтение входных регистров
MB_R_IN_REGS = 0x03, ///< Чтение регистров хранения
#endif
// writting
MB_W_COIL = 0x05, ///< Запись битовой ячейки
MB_W_HOLD_REG = 0x06, ///< Запись одиночного регистра
MB_W_COILS = 0x0F, ///< Запись нескольких битовых ячеек
MB_W_HOLD_REGS = 0x10, ///< Запись нескольких регистров
MB_R_DIAGNOSTIC = 0x08, ///< Чтение диагностической информации устройства
MB_R_DEVICE_INFO = 0x2B, ///< Чтение информации об устройстве
/* ERRORS */
// error reading
MB_ERR_R_COILS = MB_R_COILS + ERR_VALUES_START, ///< Ошибка чтения битовых ячеек
MB_ERR_R_DISC_IN = MB_R_DISC_IN + ERR_VALUES_START, ///< Ошибка чтения дискретных входов
MB_ERR_R_IN_REGS = MB_R_IN_REGS + ERR_VALUES_START, ///< Ошибка чтения регистров хранения
MB_ERR_R_HOLD_REGS = MB_R_HOLD_REGS + ERR_VALUES_START, ///< Ошибка чтения входных регистров
// error writting
MB_ERR_W_COIL = MB_W_COIL + ERR_VALUES_START, ///< Ошибка записи битовой ячейки
MB_ERR_W_HOLD_REG = MB_W_HOLD_REG + ERR_VALUES_START, ///< Ошибка записи одиночного регистра
MB_ERR_W_COILS = MB_W_COILS + ERR_VALUES_START, ///< Ошибка записи нескольких битовых ячеек
MB_ERR_W_HOLD_REGS = MB_W_HOLD_REGS + ERR_VALUES_START, ///< Ошибка записи нескольких регистров
MB_ERR_R_DIAGNOSTIC = MB_R_DIAGNOSTIC + ERR_VALUES_START, ///< Ошибка чтения диагностической информации устройства
MB_ERR_R_DEVICE_INFO = MB_R_DEVICE_INFO + ERR_VALUES_START, ///< Ошибка чтения информации об устройстве
}MB_FunctonTypeDef;
/** @brief Structure for MEI func codes */
typedef enum //MB_FunctonTypeDef
{
MEI_DEVICE_IDENTIFICATION = 0x0E,
}MB_MEITypeDef;
/** @brief Structure for comformity */
typedef enum //MB_FunctonTypeDef
{
MB_BASIC_IDENTIFICATION = 0x01, /*!< @brief Basic Device Identification.
@details All objects of this category are mandatory:
VendorName,Product code, and revision number */
MB_REGULAR_IDENTIFICATION = 0x02, /*!< @brief Regular Device Identification.
@details The device provides additional and optional
identification and description data objects */
MB_EXTENDED_IDENTIFICATION = 0x03, /*!< @brief Extended Device Identification.
@details The device provides additional and optional
identification and description private data about the physical
device itself. All of these data are device dependent. */
MB_SPEDIFIC_IDENTIFICATION = 0x04, /*!< @brief Specific Device Identification.
@details The device provides one specific identification object. */
/* ERRORS */
MB_ERR_BASIC_IDENTIFICATION = MB_BASIC_IDENTIFICATION + ERR_VALUES_START,
MB_ERR_REGULAR_IDENTIFICATION = MB_REGULAR_IDENTIFICATION + ERR_VALUES_START,
MB_ERR_EXTENDED_IDENTIFICATION = MB_REGULAR_IDENTIFICATION + ERR_VALUES_START,
MB_ERR_SPEDIFIC_IDENTIFICATION = MB_REGULAR_IDENTIFICATION + ERR_VALUES_START,
}MB_ConformityTypeDef;
/** @brief Structure for decive identification message type */
typedef struct
{
MB_MEITypeDef MEI_Type; ///< MEI Type assigned number for Device Identification Interface
MB_ConformityTypeDef ReadDevId;
MB_ConformityTypeDef Conformity;
uint8_t MoreFollows;
uint8_t NextObjId;
uint8_t NumbOfObj;
}MB_DevIdMsgTypeDef;
/** @brief Structure for modbus messsage */
typedef struct // RS_MsgTypeDef
{
uint8_t MbAddr; ///< Modbus Slave Address
MB_FunctonTypeDef Func_Code; ///< Modbus Function Code
MB_DevIdMsgTypeDef DevId; ///< Read Device Identification Header struct
uint16_t Addr; ///< Modbus Address of data
uint16_t Qnt; ///< Quantity of modbus data
uint8_t ByteCnt; ///< Quantity of bytes of data in message to transmit/receive
uint16_t DATA[DATA_SIZE]; ///< Modbus Data
MB_ExceptionTypeDef Except_Code; ///< Exception Code for the command
uint16_t MB_CRC; ///< Modbus CRC
}RS_MsgTypeDef;
//--------------------------------------------------
extern RS_MsgTypeDef MODBUS_MSG;
////////////////////---MODBUS MESSAGE DEFINES---/////////////////////
/////////////////////////////////////////////////////////////////////
////////////////////---MODBUS FUNCTION DEFINES---////////////////////
/**
* @brief Macros to set pointer to 16-bit array
* @param _arr_ - массив регистров (16-бит).
*/
#define MB_Set_Arr16_Ptr(_arr_) ((uint16_t*)(&(_arr_)))
/**
* @brief Macros to set pointer to register
* @param _parr_ - массив регистров.
* @param _addr_ - Номер регистра (его индекс) от начала массива _arr_.
*/
#define MB_Set_Register_Ptr(_parr_, _addr_) ((uint16_t *)(_parr_)+(_addr_))
/** GENERAL_MODBUS_STUFF
* @}
*/
//------------------OTHER DEFINES-------------------
#define RegisterType_Holding 0
#define RegisterType_Input 1
#define RegisterType_Discrete 2
// create hadnles and settings for uart, tim, rs with _modbus_ name
//--------------------------------------------------
#ifndef Divide_Up
/**
* @brief Calc dividing including remainder
* @param _val_ - делимое.
* @param _div_ - делитель.
* @details Если результат деления без остатка: он возвращается как есть
Если с остатком - округляется вверх
*/
//#define Divide_Up(_val_, _div_) (((_val_)%(_div_))? (_val_)/(_div_)+1 : (_val_)/_div_) /* через тернарный оператор */
#define Divide_Up(_val_, _div_) ((_val_ - 1) / _div_) + 1 /* через мат выражение */
#endif
#ifndef ByteSwap16
/**
* @brief Swap between Little Endian and Big Endian
* @param v - Переменная для свапа.
* @return v (new) - Свапнутая переменная.
* @details Переключения между двумя типами хранения слова: HI-LO байты и LO-HI байты.
*/
#define ByteSwap16(v) (((v&0xFF00) >> (8)) | ((v&0x00FF) << (8)))
#endif
////////////////////---MODBUS MESSAGE DEFINES---/////////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////////---FUNCTIONS---/////////////////////////////
//---------PROCESS MODBUS COMMAND FUNCTIONS---------
/**
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
@{
*/
/* Реализация этих функций лежит в modbus_data.c */
/* 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);
/* Define Address Origin for Input/Holding Registers */
MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, uint16_t Qnt, uint8_t RegisterType);
/* 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);
/** MODBUS_CMD_PROCESS_FUNCTIONS
* @}
*/
/////////////////////////---FUNCTIONS---/////////////////////////////
#endif //__MODBUS_CORE_H_
/** MODBUS_INTERNAL
* @}
*/

125
Inc/modbus_devid.h Normal file
View File

@@ -0,0 +1,125 @@
/**
******************************************************************************
* @file modbus_devid.h
* @brief Идентификация устройства Modbus
******************************************************************************
@addtogroup MODBUS_DEVID Device Identificators Tools
@ingroup MODBUS_INTERNAL
@{
******************************************************************************
* @details
Модуль реализации функции Read Device Identification (0x2B):
- Базовая идентификация (Vendor, Product, Revision)
- Расширенная идентификация (URL, Model, User fields)
- Поддержка потоковой передачи больших объектов
@section Объекты идентификации:
- VendorName, ProductCode, Revision - обязательные
- VendorUrl, ProductName, ModelName - опциональные
- User objects - пользовательские поля
- Поддержка до 128 пользовательских объектов
******************************************************************************/
#ifndef __MODBUS_DEVID_H_
#define __MODBUS_DEVID_H_
#include "modbus_core.h"
/////////////////////////////////////////////////////////////////////
///////////////---DEVICE IDENTIVICATIONS DEFINES---//////////////////
/** @brief Структура для объекта (идентификатора устройства модбас) */
typedef struct
{
unsigned length;
char *name;
}MB_DeviceObjectTypeDef;
/** @brief Структура со идентификаторами устройства модбас */
typedef struct
{
MB_DeviceObjectTypeDef VendorName;
MB_DeviceObjectTypeDef ProductCode;
MB_DeviceObjectTypeDef Revision;
MB_DeviceObjectTypeDef VendorUrl;
MB_DeviceObjectTypeDef ProductName;
MB_DeviceObjectTypeDef ModelName;
MB_DeviceObjectTypeDef UserApplicationName;
MB_DeviceObjectTypeDef Reserved[0x79];
MB_DeviceObjectTypeDef User[MODBUS_NUMB_OF_USEROBJECTS];
}MB_DeviceIdentificationTypeDef;
extern MB_DeviceIdentificationTypeDef MB_DEVID;
void MB_DeviceInentificationInit(void);
///////////////---DEVICE IDENTIVICATIONS DEFINES---//////////////////
/////////////////////////////////////////////////////////////////////
/////////////////---DEVICE DIAGNOSTICS DEFINES---////////////////////
/** @brief Структура со диагностической информацией устройства модбас */
typedef struct
{
uint16_t DiagnosticRegister;
struct
{
uint16_t BusMessage;
uint16_t BusCommunicationErr;
uint16_t BusExceptionErr;
uint16_t SlaveMessage;
uint16_t SlaveNoResponse;
uint16_t SlaveNAK;
uint16_t SlaveBusy;
uint16_t BusCharacterOverrun;
}Counters;
}MB_DiagnosticsInfoTypeDef;
extern MB_DiagnosticsInfoTypeDef MB_DINFO;
/////////////////---DEVICE DIAGNOSTICS DEFINES---////////////////////
/////////////////////////////////////////////////////////////////////
////////////////////---MODBUS FUNCTION DEFINES---////////////////////
/**
* @brief Инициализация объектов
* @details С помозью этого дефайна инициализируются объекты в @ref MB_DeviceInentificationInit
*/
#define MB_ObjectInit(_p_obj_, _userstring_) (_p_obj_)->length = sizeof(_userstring_);\
(_p_obj_)->name = _userstring_;
/**
* @brief Инициализация пользовательских объектов
* @details С помозью этого дефайна инициализируются пользовательские объекты в MB_DeviceInentificationInit
*/
#define MB_UserObjectInit(_pinfostruct_, _user_numb_) MB_ObjectInit(&(_pinfostruct_)->User[_user_numb_], MODBUS_USEROBJECT##_user_numb_##_NAME)
////////////////////---MODBUS MESSAGE DEFINES---/////////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////////---FUNCTIONS---/////////////////////////////
//---------PROCESS MODBUS COMMAND FUNCTIONS---------
/**
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
@{
*/
/* Write Object of Device Identification to MessageData */
void MB_WriteSingleObjectToMessage(char *mbdata, unsigned *ind, MB_DeviceObjectTypeDef *obj);
/* Write Object of Device Identification to MessageData */
void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj);
/* Proccess command Read Device Identification (43/14 - 0x2B/0E) */
uint8_t MB_Proccess_Read_Device_Identification(RS_MsgTypeDef *modbus_msg);
/** MODBUS_CMD_PROCESS_FUNCTIONS
* @}
*/
/////////////////////////---FUNCTIONS---/////////////////////////////
#endif //__MODBUS_DEVID_H_
/** MODBUS_DEVID
* @}
*/

48
Inc/modbus_holdregs.h Normal file
View File

@@ -0,0 +1,48 @@
/**
******************************************************************************
* @file modbus_holdregs.h
* @brief Работа с регистрами хранения Modbus
******************************************************************************
@addtogroup MODBUS_INS Input Register Tools
@ingroup MODBUS_INTERNAL
@{
******************************************************************************
* @details
Модуль обработки команд для регистров хранения (Holding Registers):
- Чтение множества регистров (0x03)
- Запись одиночного регистра (0x06)
- Запись множества регистров (0x10)
@section Регистры хранения:
- Read/Write доступ
- 16-битные значения (uint16_t)
******************************************************************************/
#ifndef __MODBUS_HOLDREGS_H_
#define __MODBUS_HOLDREGS_H_
#include "modbus_core.h"
/////////////////////////////////////////////////////////////////////
/////////////////////////---FUNCTIONS---/////////////////////////////
//---------PROCESS MODBUS COMMAND FUNCTIONS---------
/**
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS
@{
*/
/* Proccess command Read Holding Registers (03 - 0x03) */
uint8_t MB_Proccess_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg);
/* Proccess command Write Single Coils (06 - 0x06) */
uint8_t MB_Proccess_Write_Single_Reg(RS_MsgTypeDef *modbus_msg);
/* Proccess command Write Multiple Register (16 - 0x10) */
uint8_t MB_Proccess_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg);
/** MODBUS_CMD_PROCESS_FUNCTIONS
* @}
*/
/////////////////////////---FUNCTIONS---/////////////////////////////
#endif //__MODBUS_HOLDREGS_H_
/** MODBUS_INS
* @}
*/

43
Inc/modbus_inputregs.h Normal file
View File

@@ -0,0 +1,43 @@
/**
******************************************************************************
* @file modbus_inputregs.h
* @brief Работа с входными регистрами Modbus
******************************************************************************
@addtogroup MODBUS_HOLD Holding Registers Tools
@ingroup MODBUS_INTERNAL
@{
******************************************************************************
* @details
Модуль обработки команд для входных регистров (Input Registers):
- Чтение множества регистров (0x04)
@section Входные регистры:
- Read-Only доступ
- 16-битные значения
******************************************************************************/
#ifndef __MODBUS_INPUTREGS_H_
#define __MODBUS_INPUTREGS_H_
#include "modbus_core.h"
/////////////////////////////////////////////////////////////////////
/////////////////////////---FUNCTIONS---/////////////////////////////
//---------PROCESS MODBUS COMMAND FUNCTIONS---------
/**
* @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS Proccess Functions
* @ingroup MODBUS_FUNCTIONS
* @brief Функции обработки запросов модбас
@{
*/
/* Proccess command Read Input Registers (04 - 0x04) */
uint8_t MB_Proccess_Read_Input_Regs(RS_MsgTypeDef *modbus_msg);
/** MODBUS_CMD_PROCESS_FUNCTIONS
* @}
*/
/////////////////////////---FUNCTIONS---/////////////////////////////
#endif //__MODBUS_INPUTREGS_H_
/** MODBUS_HOLD
* @}
*/

298
Inc/rs_message.h Normal file
View File

@@ -0,0 +1,298 @@
/**
******************************************************************************
* @file rs_message.h
* @brief Библиотека обмена сообщениями по RS-интерфейсу
******************************************************************************
@defgroup RS_TOOLS RS Tools
@brief Всякое для работы по UART/RS
@{
******************************************************************************
* @details
Универсальная библиотека для работы с последовательными протоколами (Modbus, Custom)
через UART в режиме прерываний с поддержкой таймаутов.
@section Основные возможности:
- Прием/передача в прерываниях
- Обработка IDLE линии для определения конца фрейма
- Таймауты приема через TIM
- Гибкая настройка размера сообщений
@section Использование:
1. Определить структуру сообщения и размеры буфера
2. Реализовать weak-функции обработки сообщений
3. Добавить вызовы RS_UART_Handler/RS_TIM_Handler в прерывания
4. Инициализировать через RS_Init() и запустить прием RS_Receive_IT()
@section Особенности:
- Буфер: RS_Buffer[MSG_SIZE_MAX] Общий для приема/передачи
- Состояния: отслеживается через флаги в RS_HandleTypeDef
- Таймауты: контролируют максимальное время ожидания фрейма
******************************************************************************/
#ifndef __RS_LIB_H_
#define __RS_LIB_H_
#include "modbus_core.h"
/////////////////////////////////////////////////////////////////////
////////////////////////////---DEFINES---////////////////////////////
/* Check that all defines required by RS are defined */
#ifndef MSG_SIZE_MAX
#error Define MSG_SIZE_MAX (Maximum size of message). This is necessary to create buffer for UART.
#endif
#ifndef RX_FIRST_PART_SIZE
#error Define RX_FIRST_PART_SIZE (Size of first part of message). This is necessary to receive the first part of the message, from which determine the size of the remaining part of the message.
#endif
/**
* @cond Заглушки и внутренний недокументированный стаф
*/
/* Clear message-uart buffer */
#define RS_Clear_Buff(_buff_) for(int i=0; i<MSG_SIZE_MAX;i++) _buff_[i] = NULL
/* Set/Reset flags */
#define RS_Set_Free(_hRS_) _hRS_->f.RS_Busy = 0
#define RS_Set_Busy(_hRS_) _hRS_->f.RS_Busy = 1
#define RS_Set_RX_Flags(_hRS_) _hRS_->f.RX_Busy = 1; _hRS_->f.RX_Done = 0; _hRS_->f.RX_Half = 0
#define RS_Set_RX_Active_Flags(_hRS_) _hRS_->f.RX_Ongoing = 1
#define RS_Set_TX_Flags(_hRS_) _hRS_->f.TX_Busy = 1; _hRS_->f.TX_Done = 0
#define RS_Reset_RX_Active_Flags(_hRS_) _hRS_->f.RX_Ongoing = 0
#define RS_Reset_RX_Flags(_hRS_) RS_Reset_RX_Active_Flags(_hRS_); _hRS_->f.RX_Busy = 0; _hRS_->f.RX_Done = 0; _hRS_->f.RX_Half = 0
#define RS_Reset_TX_Flags(_hRS_) _hRS_->f.TX_Busy = 0; _hRS_->f.TX_Done = 0
#define RS_Set_RX_End_Flag(_hRS_) _hRS_->f.RX_Done = 1;
#define RS_Set_TX_End_Flag(_hRS_) _hRS_->f.TX_Done = 1
#define RS_Set_RX_End(_hRS_) RS_Reset_RX_Flags(_hRS_); RS_Set_RX_End_Flag(_hRS_)
#define RS_Set_TX_End(_hRS_) RS_Reset_TX_Flags(_hRS_); RS_Set_TX_End_Flag(_hRS_)
/* 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 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 RS_Is_RX_Busy(_hRS_) (_hRS_->f.RX_Busy == 1)
#define RS_Is_TX_Busy(_hRS_) (_hRS_->f.TX_Busy == 1)
// направление передачи rs485
#ifndef RS_EnableReceive
#define RS_EnableReceive()
#endif
#ifndef RS_EnableTransmit
#define RS_EnableTransmit()
#endif
#ifndef __MYLIBS_INCLUDE_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_)
#ifndef printf_rs_err
#define printf_rs_err(...)
#endif
#ifndef printf_rs
#define printf_rs(...)
#endif
#endif
#ifndef RS_USER_VARS_NUMB
#define RS_USER_VARS_NUMB 0
#endif
/** @endcond */
////////////////////////////---DEFINES---////////////////////////////
/////////////////////////////////////////////////////////////////////
///////////////////////---STRUCTURES & ENUMS---//////////////////////
//------------------ENUMERATIONS--------------------
/** @brief Enums for respond CMD about RS status */
typedef enum // RS_StatusTypeDef
{
/* IN-CODE STATUS (start from 0x01, and goes up)*/
/*0x01*/ RS_OK = 0x01,
/*0x02*/ RS_ERR,
/*0x03*/ RS_ABORTED,
/*0x04*/ RS_BUSY,
/*0x05*/ RS_SKIP,
/*0x06*/ RS_COLLECT_MSG_ERR,
/*0x07*/ RS_PARSE_MSG_ERR,
// reserved values
// /*0x00*/ RS_UNKNOWN_ERR = 0x00, ///< reserved for case, if no one error founded (nothing changed response from zero)
}RS_StatusTypeDef;
#define RS_MASTER_START 0x3
/** @brief Enums for RS Modes */
typedef enum // RS_ModeTypeDef
{
RS_SLAVE_ALWAYS_WAIT = 0x01, ///< Slave mode with infinity waiting
RS_SLAVE_TIMEOUT_WAIT = 0x02, ///< Slave mode with waiting with timeout
// RS_MASTER = 0x03, ///< Master mode
}RS_ModeTypeDef;
/** @brief Enums for RS UART Modes */
typedef enum // RS_ITModeTypeDef
{
BLCK_MODE = 0x00, ///< Blocking mode
IT_MODE = 0x01, ///< Interrupt mode
}RS_ITModeTypeDef;
/** @brief Enums for Abort modes */
typedef enum // RS_AbortTypeDef
{
ABORT_TX = 0x01, ///< Abort transmit
ABORT_RX = 0x02, ///< Abort receive
ABORT_RX_TX = 0x03, ///< Abort receive and transmit
ABORT_RS = 0x04, ///< Abort uart and reset RS structure
}RS_AbortTypeDef;
/** @brief Enums for RX Size modes */
typedef enum // RS_RXSizeTypeDef
{
RS_RX_Size_Const = 0x01, ///< size of receiving message is constant
RS_RX_Size_NotConst = 0x02, ///< size of receiving message isnt constant
}RS_RXSizeTypeDef;
//-----------STRUCTURE FOR HANDLE RS------------
/** @brief Struct for flags RS */
typedef struct
{
unsigned RX_Half:1; ///< flag: 0 - receiving msg before ByteCnt, 0 - receiving msg after ByteCnt
unsigned RS_Busy:1; ///< flag: 1 - RS is busy, 0 - RS isnt busy
unsigned RX_Ongoing:1; ///< flag: 1 - receiving data right now, 0 - waiting for receiving data
unsigned RX_Busy:1; ///< flag: 1 - receiving is active, 0 - receiving isnt active
unsigned TX_Busy:1; ///< flag: 1 - transmiting is active, 0 - transmiting isnt active
unsigned RX_Done:1; ///< flag: 1 - receiving is done, 0 - receiving isnt done
unsigned TX_Done:1; ///< flag: 1 - transmiting is done, 0 - transmiting isnt done
// setted by user
unsigned RX_Continue:1; ///< flag: 0 - continue receiving, 0 - start receiving from ind = 0
unsigned MessageHandled:1; ///< flag: 1 - RS command is handled, 0 - RS command isnt handled yet
unsigned EchoResponse:1; ///< flag: 1 - response with received msg, 0 - response with own msg
unsigned DeferredResponse:1; ///< flag: 1 - response not in interrupt, 0 - response in interrupt
unsigned DataUpdated:1; ///< flag: 1 - Received command to write colis/resg
unsigned ReInit_UART:1; ///< flag: 1 - need to reinitialize uart, 0 - nothing
}RS_FlagsTypeDef;
/**
* @brief Handle for RS communication.
* @note Prefixes: h - handle, s - settings, f - flag
*/
typedef struct // RS_HandleTypeDef
{
/* MESSAGE */
uint8_t ID; ///< ID of RS "channel"
RS_MsgTypeDef *pMessagePtr; ///< pointer to message struct
uint8_t *pBufferPtr; ///< pointer to message buffer
int32_t RS_Message_Size; ///< size of whole message, not only data
/* HANDLERS and SETTINGS */
UART_HandleTypeDef *huart; ///< handler for used uart
TIM_HandleTypeDef *htim; ///< handler for used tim
RS_ModeTypeDef sRS_Mode; ///< setting: slave or master @ref RS_ModeTypeDef
RS_ITModeTypeDef sRS_IT_Mode; ///< setting: 1 - IT mode, 0 - Blocking mode
uint16_t sRS_Timeout; ///< setting: timeout in ms
RS_RXSizeTypeDef sRS_RX_Size_Mode; ///< setting: 1 - not const, 0 - const
/* FLAGS */
RS_FlagsTypeDef f; ///< These flags for controling receive/transmit
/* RS STATUS */
uint32_t lastPacketTick;
RS_StatusTypeDef RS_STATUS; ///< RS status
TrackerTypeDef(RS_USER_VARS_NUMB) rs_err;
}RS_HandleTypeDef;
extern RS_HandleTypeDef hmodbus1;
///////////////////////---STRUCTURES & ENUMS---//////////////////////
/////////////////////////////////////////////////////////////////////
///////////////////////////---FUNCTIONS---///////////////////////////
//----------------FUNCTIONS FOR PROCESSING MESSAGE-------------------
/*--------------------Defined by users purposes--------------------*/
/* Respond accord to received message */
RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
/* Collect message in buffer to transmit it */
RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff);
/* Parse message from buffer to process it */
RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff);
//-------------------------GENERAL FUNCTIONS-------------------------
/*-----------------Should be called from main code-----------------*/
/* Start receive IT */
RS_StatusTypeDef RS_Receive_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
/* Start transmit IT */
RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
/* Initialize UART and handle RS stucture */
RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, uint8_t *pRS_BufferPtr);
/* ReInitialize UART and RS receive */
HAL_StatusTypeDef RS_ReInit_UART(RS_HandleTypeDef *hRS, UART_HandleTypeDef *suart);
/* Abort RS/UART */
RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode);
//-------------------------GENERAL FUNCTIONS-------------------------
//-------------------------------------------------------------------
//--------------------CALLBACK/HANDLER FUNCTIONS---------------------
/* Handle for starting receive */
RS_StatusTypeDef RS_Handle_Receive_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
/* Handle for starting transmit */
RS_StatusTypeDef RS_Handle_Transmit_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg);
/* UART TX Callback: define behaviour after transmiting message */
RS_StatusTypeDef RS_UART_TxCpltCallback(RS_HandleTypeDef *hRS);
/* Handler for UART */
void RS_UART_Handler(RS_HandleTypeDef *hRS);
/* Handler for TIM */
void RS_TIM_Handler(RS_HandleTypeDef *hRS);
//--------------------CALLBACK/HANDLER FUNCTIONS---------------------
///////////////////////////---FUNCTIONS---///////////////////////////
/** RS_TOOLS
* @}
*/
#endif // __RS_LIB_H_