From fbc424e507ae674751d27684b91da3097b80928f Mon Sep 17 00:00:00 2001 From: Razvalyaev Date: Tue, 4 Nov 2025 22:02:28 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=BE=D0=B4=D1=82=D1=8F=D0=B3=D0=B8?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=B2=D1=81=D0=B5=D1=85=20?= =?UTF-8?q?=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D0=B9=20=D1=81?= =?UTF-8?q?=20=D1=80=D0=B5=D0=BB=D0=B8=D0=B7=D0=B0=20=D0=B2=20=D0=B2=D0=B5?= =?UTF-8?q?=D1=82=D0=BA=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Modbus/Inc/modbus.h | 74 +- Modbus/Inc/modbus_coils.h | 86 +- Modbus/Inc/modbus_config.h | 21 +- Modbus/Inc/modbus_core.h | 35 +- Modbus/Inc/modbus_devid.h | 93 +- Modbus/Inc/modbus_diag.h | 133 ++ Modbus/Inc/modbus_holdregs.h | 12 +- Modbus/Inc/modbus_inputregs.h | 6 +- Modbus/Inc/modbus_master.h | 121 ++ Modbus/Inc/modbus_slave.h | 34 + Modbus/Inc/rs_message.h | 161 +- Modbus/Src/modbus.c | 521 +---- Modbus/Src/modbus_coils.c | 64 +- Modbus/Src/modbus_data.c | 6 +- Modbus/Src/modbus_devid.c | 164 +- Modbus/Src/modbus_diag.c | 328 +++ Modbus/Src/modbus_holdregs.c | 24 +- Modbus/Src/modbus_inputregs.c | 13 +- Modbus/Src/modbus_master.c | 519 +++++ Modbus/Src/modbus_slave.c | 437 ++++ Modbus/Src/rs_message.c | 210 +- STM32F103_Example/Core/Src/main.c | 12 +- .../MDK-ARM/Modbus_example.uvguix.wot89 | 1923 +++++++++++++++++ .../MDK-ARM/Modbus_example.uvoptx | 254 ++- .../MDK-ARM/Modbus_example.uvprojx | 55 +- 25 files changed, 4410 insertions(+), 896 deletions(-) create mode 100644 Modbus/Inc/modbus_diag.h create mode 100644 Modbus/Inc/modbus_master.h create mode 100644 Modbus/Inc/modbus_slave.h create mode 100644 Modbus/Src/modbus_diag.c create mode 100644 Modbus/Src/modbus_master.c create mode 100644 Modbus/Src/modbus_slave.c create mode 100644 STM32F103_Example/MDK-ARM/Modbus_example.uvguix.wot89 diff --git a/Modbus/Inc/modbus.h b/Modbus/Inc/modbus.h index 568bf1d..e9af0ac 100644 --- a/Modbus/Inc/modbus.h +++ b/Modbus/Inc/modbus.h @@ -5,7 +5,7 @@ ****************************************************************************** @addtogroup MODBUS Modbus tools ****************************************************************************** -@addtogroup MODBUS_FUNCTIONS Modbus library funtions +@addtogroup MODBUS_FUNCTIONS Main API for Modbus Library @ingroup MODBUS @{ ****************************************************************************** @@ -17,35 +17,45 @@ @section Инструкция по подключению Для корректной работы надо: - Подключить обработчики RS_UART_Handler(), RS_TIM_Handler(), в соответствубщие - низкоуровневые прерывания UART_IRQHandler, TIM_IRQHandler. Вместо HAL'овского обработчика + низкоуровневые прерывания UART_IRQHandler, TIM_IRQHandler вместо HAL'овского обработчика -В modbus_config.h настроить дефайны для нужной работы UART +- В modbus_config.h настроить дефайны для нужной работы UART -- Инициализировать хендл мобдас. По умолчанию глобально создается hmodbus1, но можно сделать свой -После для запуска Modbus: -@verbatim -//----------------Прием модбас----------------// -#include "modbus.h" +- Инициализировать хендл мобдас. По умолчанию глобально создается hmodbus1 +- После для запуска Modbus: + @verbatim + //----------------Слейв модбас----------------// + #include "modbus.h" -MODBUS_SetupHardware(&hmodbus1, &huart1, &htim3); -MODBUS_SlaveStart(&hmodbus1, NULL); -// или если нужно переключится на другой -@endverbatim + MODBUS_FirstInit(&hmodbus1, &huart1, &htim3); + MODBUS_Config(&hmodbus1, 1, 1000, MODBUS_MODE_SLAVE); + MODBUS_SlaveStart(&hmodbus1, NULL); + @endverbatim + @verbatim + //----------------Мастер модбас----------------// + #include "modbus.h" + + MODBUS_FirstInit(&hmodbus1, &huart1, &htim3); + MODBUS_Config(&hmodbus1, 0, 1000, MODBUS_MODE_MASTER); // - если нужны другие настройки, не из modbus_config.h + // Запрос на 1 ID, считать холдинг регистры с 0 адреса 10 штук + RS_MsgTypeDef msg = MB_REQUEST_READ_HOLDING_REGS(1, 0, 10); + MODBUS_MasterRequest(&hmodbus1, &msg, &callback_func); + + void callback_func(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) + { + // modbus_msg содержит ответ от устройства + } + @endverbatim @section Подключаемые модули: +- rs_message.h - работа с uart - 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() +- modbus_diag.h - диагностика modbus @section Структура данных Modbus @@ -62,12 +72,14 @@ MODBUS_SlaveStart(&hmodbus1, NULL); #ifndef __MODBUS_H_ #define __MODBUS_H_ -#include "__crc_algs.h" #include "rs_message.h" +#include "modbus_master.h" +#include "modbus_slave.h" #include "modbus_coils.h" #include "modbus_holdregs.h" #include "modbus_inputregs.h" #include "modbus_devid.h" +#include "modbus_diag.h" @@ -76,20 +88,16 @@ MODBUS_SlaveStart(&hmodbus1, NULL); //----------------FUNCTIONS FOR USER---------------- -/** - * @addtogroup MODBUS_INIT_FUNCTIONS Functions for Init - * @ingroup MODBUS_FUNCTIONS - * @brief Функции для инициализации - @{ - */ -/* Инициализация периферии модбас. */ -void MODBUS_SetupHardware(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim); -/* Программная конфигурация модбас. */ -void MODBUS_Config(RS_HandleTypeDef *hmodbus, uint8_t ID, uint16_t Timeout, uint8_t master); -/** MODBUS_INIT_FUNCTIONS - * @} - */ +/* Инициализация периферии модбас. */ +HAL_StatusTypeDef MODBUS_FirstInit(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim); +/* Программная конфигурация модбас. */ +HAL_StatusTypeDef MODBUS_Config(RS_HandleTypeDef *hmodbus, uint8_t ID, uint16_t Timeout, uint8_t master); +/* Запуск слейв устройства */ +HAL_StatusTypeDef MODBUS_SlaveStart(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg); +/* Реквест мастера модбас */ +HAL_StatusTypeDef MODBUS_MasterRequest(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, void (*pClbk)(RS_HandleTypeDef*, RS_MsgTypeDef*)); + //---------PROCESS MODBUS COMMAND FUNCTIONS--------- /////////////////////////---FUNCTIONS---///////////////////////////// diff --git a/Modbus/Inc/modbus_coils.h b/Modbus/Inc/modbus_coils.h index 7dff15d..95f4a14 100644 --- a/Modbus/Inc/modbus_coils.h +++ b/Modbus/Inc/modbus_coils.h @@ -42,13 +42,14 @@ typedef enum //-------------------------------------------------- /** - * @brief Macros to set pointer to a certain register that contains certain coil - * @param _parr_ - массив коилов. - * @param _coil_ - Номер коила от начала массива _arr_. + * @brief Макрос для установки указателя на регистр, содержащий запрашиваемый коил + * @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 + - (_coil_/16) - индекс регистра, в котором содержится коил по адресу _coil_ + +Визуальный пример: 30 коил будет в 30/16 = 1 регистре (индексация с 0) xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx |register[0]----| |register[1]----| |skip this------| |get this-------| @@ -57,15 +58,17 @@ typedef enum */ #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_. + * @brief Макрос для установки маски, чтобы выделить запрашиваемый коил из регистра + * @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) + - (16*(_coil_/16) - сколько коилов нужно пропустить. прим. (16*30/16) - первые 16 коилов находятся вне регистра + - _coil_-(16*(_coil_/16)) - сдвинуть бит на место запрашиваемого коила в регистре - Visual explanation: 30th coil in coils registers array + Визуальный пример: 30 коил будет регистре[1], на 14 бите: + register = 30/16 = 1 + bit = 30 - (16*30/16) = 30 - 16 = 14 + xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx |register[0]----| |register[1]----| |skip this------| |get this-------| @@ -79,14 +82,49 @@ typedef enum /////////////////////////---FUNCTIONS---///////////////////////////// /** -* @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS Modbus Data Access +* @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS API for Data Access * @ingroup MODBUS_FUNCTIONS -* @brief Функции для доступа к данным модбас (коилы) +* @brief Функции для доступа к данным модбас @{ */ + + +/** + * @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_GetCoilState(&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_GetCoilState(&MODBUS_MSG, addr, &state)) + * { + * printf("Coil %d: %s\n", addr, state ? "ON" : "OFF"); + * } + * } + * @endcode + */ + +int MB_GetCoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coil_state); + +/** MODBUS_REQ_COILS_API + * @} + */ + + /** - * @brief Read Coil at its local address. + * @brief Считать коил по локальному адресу. * @param _parr_ - массив коилов. * @param _coil_ - Номер коила от начала массива _arr_. * @return uint16_t Возвращает запрошенный коил на 0м бите. @@ -95,7 +133,7 @@ typedef enum */ #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. + * @brief Выставить коил по локальному адресу. * @param _parr_ Указатель на массив коилов. * @param _coil_ - Номер коила от начала массива _arr_. * @@ -103,7 +141,7 @@ typedef enum */ #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. + * @brief Сбросить коил по локальному адресу. * @param _parr_ Указатель на массив коилов. * @param _coil_ - Номер коила от начала массива _arr_. * @@ -111,7 +149,7 @@ typedef enum */ #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. + * @brief Переключить состояние коила по локальному адресу. * @param _parr_ Указатель на массив коилов. * @param _coil_ - Номер коила от начала массива _arr_. * @@ -119,9 +157,9 @@ typedef enum */ #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 @@ -133,11 +171,11 @@ uint16_t MB_Read_Coil_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception); * @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) */ +/* Обработать функцию Read Coils (01 - 0x01) */ +uint8_t MB_Process_Read_Coils(RS_MsgTypeDef *modbus_msg); +/* Обработать функцию Write Single Coils (05 - 0x05) */ +uint8_t MB_Process_Write_Single_Coil(RS_MsgTypeDef *modbus_msg); +/* Обработать функцию Write Multiple Coils (15 - 0x0F) */ uint8_t MB_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg); /** MODBUS_CMD_PROCESS_FUNCTIONS diff --git a/Modbus/Inc/modbus_config.h b/Modbus/Inc/modbus_config.h index 1fde03f..caa8f3e 100644 --- a/Modbus/Inc/modbus_config.h +++ b/Modbus/Inc/modbus_config.h @@ -25,17 +25,30 @@ // Строковые идентификаторы устройства #define MODBUS_VENDOR_NAME "NIO-12" #define MODBUS_PRODUCT_CODE "" -#define MODBUS_REVISION "Ver. 1.0" +#define MODBUS_REVISION "" #define MODBUS_VENDOR_URL "" #define MODBUS_PRODUCT_NAME "" -#define MODBUS_MODEL_NAME "STM32F103" +#define MODBUS_MODEL_NAME "" #define MODBUS_USER_APPLICATION_NAME "" #define MODBUS_NUMB_OF_USEROBJECTS 0 // Периферия (опционально) #define mb_huart huart1 ///< Удобный дефайн для модбасовского uart -#define mb_htim htim3 ///< Удобный дефайн для модбасовского таймера -///< +#define mb_htim htim2 ///< Удобный дефайн для модбасовского таймера +//#define RS_EnableReceive() ///< Функция изменения направления передачи на ПРИЕМ для RS-485 +//#define RS_EnableTransmit() ///< Функция изменения направления передачи на ПЕРЕДАЧУ для RS-485 + + +// Модули modbus +#define MODBUS_ENABLE_SLAVE ///< Включить обработку МАСТЕР режима +//#define MODBUS_ENABLE_MASTER ///< Включить обработку СЛЕЙВ режима + +#define MODBUS_ENABLE_COILS ///< Включить обработку коилов +#define MODBUS_ENABLE_HOLDINGS ///< Включить обработку регистров хранения +#define MODBUS_ENABLE_INPUTS ///< Включить обработку входных регистров +#define MODBUS_ENABLE_DEVICE_IDENTIFICATORS ///< Включить обработку идентификаторы устройства +#define MODBUS_ENABLE_DIAGNOSTICS ///< Включить обработку диагностики модбас + /** * @brief Поменять комманды 0x03 и 0x04 местами (для LabView терминалки от двигателей) diff --git a/Modbus/Inc/modbus_core.h b/Modbus/Inc/modbus_core.h index dabc870..6a34751 100644 --- a/Modbus/Inc/modbus_core.h +++ b/Modbus/Inc/modbus_core.h @@ -27,6 +27,7 @@ #include "modbus_config.h" #include "modbus_data.h" +#include "__crc_algs.h" /** * @addtogroup MODBUS_MESSAGE_DEFINES Modbus Message Tools @@ -93,8 +94,8 @@ typedef enum //MB_FunctonTypeDef MB_W_COILS = 0x0F, ///< Запись нескольких битовых ячеек MB_W_HOLD_REGS = 0x10, ///< Запись нескольких регистров - MB_R_DIAGNOSTIC = 0x08, ///< Чтение диагностической информации устройства - MB_R_DEVICE_INFO = 0x2B, ///< Чтение информации об устройстве + MB_R_DIAGNOSTIC = 0x08, ///< Чтение диагностической информации устройства + MB_R_DEVICE_INFO = 0x2B, ///< Чтение информации об устройстве /* ERRORS */ // error reading @@ -116,39 +117,39 @@ typedef enum //MB_FunctonTypeDef /** @brief Structure for MEI func codes */ typedef enum //MB_FunctonTypeDef { - MEI_DEVICE_IDENTIFICATION = 0x0E, + MEI_DEVICE_IDENTIFICATIONS = 0x0E, }MB_MEITypeDef; /** @brief Structure for comformity */ typedef enum //MB_FunctonTypeDef { - MB_BASIC_IDENTIFICATION = 0x01, /*!< @brief Basic Device Identification. + MB_BASIC_IDENTIFICATIONS = 0x01, /*!< @brief Basic Device Identifications. @details All objects of this category are mandatory: VendorName,Product code, and revision number */ - MB_REGULAR_IDENTIFICATION = 0x02, /*!< @brief Regular Device Identification. + MB_REGULAR_IDENTIFICATIONS = 0x02, /*!< @brief Regular Device Identifications. @details The device provides additional and optional - identification and description data objects */ + identifications and description data objects */ - MB_EXTENDED_IDENTIFICATION = 0x03, /*!< @brief Extended Device Identification. + MB_EXTENDED_IDENTIFICATIONS = 0x03, /*!< @brief Extended Device Identifications. @details The device provides additional and optional - identification and description private data about the physical + identifications and description private data about the physical device itself. All of these data are device dependent. */ - MB_SPEDIFIC_IDENTIFICATION = 0x04, /*!< @brief Specific Device Identification. - @details The device provides one specific identification object. */ + MB_SPEDIFIC_IDENTIFICATIONS = 0x04, /*!< @brief Specific Device Identifications. + @details The device provides one specific identifications 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_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 identification message type */ +/** @brief Structure for decive identifications message type */ typedef struct { - MB_MEITypeDef MEI_Type; ///< MEI Type assigned number for Device Identification Interface + MB_MEITypeDef MEI_Type; ///< MEI Type assigned number for Device Identifications Interface MB_ConformityTypeDef ReadDevId; MB_ConformityTypeDef Conformity; uint8_t MoreFollows; @@ -162,7 +163,7 @@ 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 + MB_DevIdMsgTypeDef DevId; ///< Read Device Identifications 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 diff --git a/Modbus/Inc/modbus_devid.h b/Modbus/Inc/modbus_devid.h index 7d4361b..b1c8b2b 100644 --- a/Modbus/Inc/modbus_devid.h +++ b/Modbus/Inc/modbus_devid.h @@ -1,14 +1,14 @@ /** ****************************************************************************** * @file modbus_devid.h -* @brief Идентификация устройства Modbus +* @brief Идентификаторы устройства Modbus ****************************************************************************** -@addtogroup MODBUS_DEVID Device Identificators Tools +@addtogroup MODBUS_DEVID Device Identifications Tools @ingroup MODBUS_INTERNAL @{ ****************************************************************************** * @details -Модуль реализации функции Read Device Identification (0x2B): +Модуль реализации функции Read Device Identifications (0x2B): - Базовая идентификация (Vendor, Product, Revision) - Расширенная идентификация (URL, Model, User fields) - Поддержка потоковой передачи больших объектов @@ -48,35 +48,11 @@ typedef struct MB_DeviceObjectTypeDef Reserved[0x79]; MB_DeviceObjectTypeDef User[MODBUS_NUMB_OF_USEROBJECTS]; -}MB_DeviceIdentificationTypeDef; -extern MB_DeviceIdentificationTypeDef MB_DEVID; +}MB_DeviceIdentificationsTypeDef; +extern MB_DeviceIdentificationsTypeDef 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---//////////////////// @@ -101,18 +77,65 @@ extern MB_DiagnosticsInfoTypeDef MB_DINFO; ///////////////////////////////////////////////////////////////////// /////////////////////////---FUNCTIONS---///////////////////////////// +/** + * @addtogroup MODBUS_REQ_DEFID_API API for Device Identifications + * @ingroup MODBUS_REQUEST_MSG + * @brief Макросы для чтения идентификторов из ответа в режиме мастер + * @details Примеры использования: + * + * @code + * // Пример 1: Получить VendorName (ID = 0x00) + * uint8_t length; + * char vendor_name[64]; + * if(MB_FindObjectById(&MODBUS_MSG, 0x00, vendor_name, &length)) + * { + * // получено + * } + * + * // Пример 2: Перебрать все объекты в сообщении + * uint8_t obj_id, obj_length; + * char obj_data[256]; + * + * int obj_count = MB_GetNumberOfObjects(&MODBUS_MSG); + * printf("Total objects: %d\n", obj_count); + * + * for(int i = 0; i < obj_count; i++) + * { + * if(MB_GetObjectByIndex(&MODBUS_MSG, i, &obj_id, obj_data, &obj_length)) + * { + * // получено + * } + * } + * @endcode + */ + +/* Получить количество объектов в сообщении */ +int MB_GetNumberOfObjects(RS_MsgTypeDef *modbus_msg); +/* Найти объект по ID в сообщении */ +int MB_FindObjectById(RS_MsgTypeDef *modbus_msg, uint8_t obj_id, char *obj_data, uint8_t *obj_length); +/* Получить объект по индексу в сообщении */ +int MB_GetObjectByIndex(RS_MsgTypeDef *modbus_msg, int index, uint8_t *obj_id, char *obj_data, uint8_t *obj_length); + + +/** MODBUS_REQ_DEFID_API +* @} +*/ + + + +/* Записать Один Объект Идентификатора в массив данных */ +void MB_WriteSingleObjectToMessage(char *mbdata, unsigned *ind, MB_DeviceObjectTypeDef *obj); +/* Записать Массив Объектов Идентификатора в массив данных */ +void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj); + //---------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); +/* Обработать функцию Read Device Identifications (43/14 - 0x2B/0E) */ +uint8_t MB_Process_Read_Device_Identifications(RS_MsgTypeDef *modbus_msg); /** MODBUS_CMD_PROCESS_FUNCTIONS * @} */ diff --git a/Modbus/Inc/modbus_diag.h b/Modbus/Inc/modbus_diag.h new file mode 100644 index 0000000..b338c67 --- /dev/null +++ b/Modbus/Inc/modbus_diag.h @@ -0,0 +1,133 @@ +/** +****************************************************************************** +* @file modbus_diag.h +* @brief Диагностика устройства Modbus +****************************************************************************** +@addtogroup MODBUS_DIAG Diagnostics Tools +@ingroup MODBUS_INTERNAL +@{ +****************************************************************************** +* @details +Модуль реализации Diagnostics (Serial Line only) (0x08): +- Полная поддержка всех подфункций диагностики +- Возможность выставить/сбросить любой бит в диагностическом регистре +- Сбор статистики работы устройства +- Управление режимами работы +******************************************************************************/ +#ifndef __MODBUS_DIAG_H_ +#define __MODBUS_DIAG_H_ +#include "modbus_core.h" + +///////////////////////////////////////////////////////////////////// +/////////////////---DEVICE DIAGNOSTICS DEFINES---//////////////////// + +/** @brief Режимы работы устройства */ +typedef enum +{ + MODBUS_NORMAL_MODE = 0, + MODBUS_LISTEN_ONLY_MODE = 1 +} MB_DeviceModeTypeDef; + + +/** @brief Структура со диагностической информацией устройства модбас */ +typedef struct +{ + uint16_t DiagnosticRegister; ///< Регистр диагностики. 0 бит - overrun. Остальное заполняется пользователем + MB_DeviceModeTypeDef DeviceMode;///< Режим устройства - NORMAL/LISTEN_ONLY + struct + { + uint16_t BusMessage; ///< Все принятые фреймы modbus на линии (с всех адресов) + uint16_t BusCommunicationErr; ///< Ошибки при приеме фрейма modbus + uint16_t BusExceptionErr; ///< Ошибки при обработке фрейма modbus + uint16_t SlaveMessage; ///< Принятые сообщения (только запросы на адрес данного устройства) + uint16_t SlaveNoResponse; ///< Счетчик сколько мы раз не ответили на запрос + uint16_t SlaveNAK; ///< Счетчик аномальной ошибки при обработке фрейма + uint16_t SlaveBusy; ///< Счетчик принятых запросов когда устройство занято. Здесь не работает: из-за архитектуры отследить невозможно + uint16_t BusCharacterOverrun; ///< Overrun Error + } Counters; +} MB_DiagnosticsInfoTypeDef; + +extern MB_DiagnosticsInfoTypeDef MB_DIAG; + +/////////////////---DEVICE DIAGNOSTICS DEFINES---//////////////////// + +///////////////////////////////////////////////////////////////////// +/////////////////////////---FUNCTIONS---///////////////////////////// + +/* Инициализация диагностических счетчиков */ +void MB_DiagnosticsInit(void); + +/** + * @addtogroup MODBUS_REQ_DIAG_API API for Diagnostics + * @ingroup MODBUS_REQUEST_MSG + * @brief API для чтения диагностической информации из ответа в режиме мастер + * @details Примеры использования: + * + * @code + * Получить данные диагностики (значение счетчика) + * uint16_t counter_value; + * if(MB_GetDiagnosticResponse(&MODBUS_MSG, &counter_value)) + * { + * printf("Counter value: %d\n", counter_value); + * } + * @endcode + */ +int MB_GetDiagnosticResponse(RS_MsgTypeDef *modbus_msg, uint16_t *data); +/** MODBUS_REQ_DIAG_API + * @} + */ + + + + + + + + +/** +* @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS +@{ +*/ + +/* Выставить бит в регистре диагностике */ +int MB_Diagnostics_WriteBit(int bit_num, int bit_state); +/*ь Прочитать состояние бита диагностического регистра */ +int MB_Diagnostics_GetBit(int bit_num); +/* Получение текущего режима устройства */ +MB_DeviceModeTypeDef MB_GetDeviceMode(void); +/** MODBUS_CMD_PROCESS_FUNCTIONS + * @} + */ + +//---------PROCESS MODBUS COMMAND FUNCTIONS--------- +/** + * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS + @{ + */ + +/* Обработка команды диагностики (0x08) */ +uint8_t MB_Process_Diagnostics(RS_MsgTypeDef *modbus_msg); + +/** MODBUS_CMD_PROCESS_FUNCTIONS + * @} + */ + + +/* Функции для обновления счетчиков диагностики */ +void MB_Diagnostics_BusMessageCnt(void); +void MB_Diagnostics_CommunicationErrorCnt(void); +void MB_Diagnostics_ExceptionErrorCnt(void); +void MB_Diagnostics_CharacterOverrunCnt(void); +void MB_Diagnostics_SlaveMessageCnt(void); +void MB_Diagnostics_SlaveNoResponseCnt(void); +void MB_Diagnostics_SlaveNAKCnt(void); +void MB_Diagnostics_SlaveBusyCnt(void); + + +/////////////////////////---FUNCTIONS---///////////////////////////// + +#endif //__MODBUS_DIAG_H_ + +/** MODBUS_DIAG + * @} + */ \ No newline at end of file diff --git a/Modbus/Inc/modbus_holdregs.h b/Modbus/Inc/modbus_holdregs.h index 2d6898e..3a4e253 100644 --- a/Modbus/Inc/modbus_holdregs.h +++ b/Modbus/Inc/modbus_holdregs.h @@ -29,12 +29,12 @@ * @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); +/* Обработать функцию Read Holding Registers (03 - 0x03) */ +uint8_t MB_Process_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg); +/* Обработать функцию Write Single Coils (06 - 0x06) */ +uint8_t MB_Process_Write_Single_Reg(RS_MsgTypeDef *modbus_msg); +/* Обработать функцию Write Multiple Register (16 - 0x10) */ +uint8_t MB_Process_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg); /** MODBUS_CMD_PROCESS_FUNCTIONS * @} diff --git a/Modbus/Inc/modbus_inputregs.h b/Modbus/Inc/modbus_inputregs.h index 53360b0..0aba2a6 100644 --- a/Modbus/Inc/modbus_inputregs.h +++ b/Modbus/Inc/modbus_inputregs.h @@ -24,13 +24,13 @@ //---------PROCESS MODBUS COMMAND FUNCTIONS--------- /** - * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS Proccess Functions + * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS Internal Process Functions * @ingroup MODBUS_FUNCTIONS * @brief Функции обработки запросов модбас @{ */ -/* Proccess command Read Input Registers (04 - 0x04) */ -uint8_t MB_Proccess_Read_Input_Regs(RS_MsgTypeDef *modbus_msg); +/* Обработать функцию Read Input Registers (04 - 0x04) */ +uint8_t MB_Process_Read_Input_Regs(RS_MsgTypeDef *modbus_msg); /** MODBUS_CMD_PROCESS_FUNCTIONS * @} diff --git a/Modbus/Inc/modbus_master.h b/Modbus/Inc/modbus_master.h new file mode 100644 index 0000000..70505ac --- /dev/null +++ b/Modbus/Inc/modbus_master.h @@ -0,0 +1,121 @@ +/** +****************************************************************************** +* @file modbus_master.h +* @brief Главный заголовочный файл Modbus библиотеки +****************************************************************************** +@addtogroup MODBUS_MASTER Modbus master funtions +@ingroup MODBUS_CMD_PROCESS_FUNCTIONS +@{ +****************************************************************************** +* @details +Модуль реализации обработки UART сообщение в режиме мастер +******************************************************************************/ +#ifndef __MODBUS_MASTER_H_ +#define __MODBUS_MASTER_H_ + +#include "rs_message.h" + +#ifdef MODBUS_ENABLE_MASTER +#define MODBUS_MODE_MASTER 1 +#endif + +/** + * @addtogroup MODBUS_REQUEST_MSG API for Master Requests + * @ingroup MODBUS_FUNCTIONS + * @brief Макросы для создания запросов в режиме мастер + * @details Примеры использования: + * + * // Чтение 10 holding registers начиная с адреса 0 + * RS_MsgTypeDef read_msg = MB_REQUEST_READ_HOLDING_REGS(1, 0, 10); + * + * // Запись одного coil + * RS_MsgTypeDef write_coil_msg = MB_REQUEST_WRITE_SINGLE_COIL(1, 5, 1); + * + * // Диагностический запрос + * RS_MsgTypeDef diag_msg = MB_REQUEST_RETURN_BUS_MESSAGE_COUNT(1); + * + * // Идентификация устройства + * RS_MsgTypeDef dev_id_msg = MB_REQUEST_READ_DEVICE_ID_BASIC(1); + */ + +//---------КЛАССИЧЕСКИЕ ДАННЫЕ----------- +RS_MsgTypeDef MB_REQUEST_READ_COILS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity); +RS_MsgTypeDef MB_REQUEST_READ_DISCRETE_INPUTS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity); +RS_MsgTypeDef MB_REQUEST_READ_HOLDING_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity); +RS_MsgTypeDef MB_REQUEST_READ_INPUT_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity); +RS_MsgTypeDef MB_REQUEST_WRITE_SINGLE_COIL(uint8_t slave_addr, uint16_t coil_addr, uint8_t value); +RS_MsgTypeDef MB_REQUEST_WRITE_SINGLE_REG(uint8_t slave_addr, uint16_t reg_addr, uint16_t value); +RS_MsgTypeDef MB_REQUEST_WRITE_MULTIPLE_COILS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity, uint8_t *coils_data); +RS_MsgTypeDef MB_REQUEST_WRITE_MULTIPLE_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity, uint16_t *regs_data); + +//---------ДИАГНОСТИЧЕСКИЕ ДАННЫЕ----------- +RS_MsgTypeDef MB_REQUEST_DIAGNOSTIC_QUERY(uint8_t slave_addr, uint16_t sub_function, uint16_t data); +RS_MsgTypeDef MB_REQUEST_RETURN_QUERY_DATA(uint8_t slave_addr); +RS_MsgTypeDef MB_REQUEST_RESTART_COMMUNICATIONS(uint8_t slave_addr, uint16_t data); +RS_MsgTypeDef MB_REQUEST_RETURN_DIAGNOSTIC_REGISTER(uint8_t slave_addr); +RS_MsgTypeDef MB_REQUEST_FORCE_LISTEN_ONLY_MODE(uint8_t slave_addr); +RS_MsgTypeDef MB_REQUEST_CLEAR_COUNTERS_AND_DIAGNOSTIC_REGISTER(uint8_t slave_addr); +RS_MsgTypeDef MB_REQUEST_RETURN_BUS_MESSAGE_COUNT(uint8_t slave_addr); +RS_MsgTypeDef MB_REQUEST_RETURN_BUS_COMMUNICATION_ERROR_COUNT(uint8_t slave_addr); +RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_EXCEPTION_ERROR_COUNT(uint8_t slave_addr); +RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_MESSAGE_COUNT(uint8_t slave_addr); +RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_NO_RESPONSE_COUNT(uint8_t slave_addr); +RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_NAK_COUNT(uint8_t slave_addr); +RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_BUSY_COUNT(uint8_t slave_addr); +RS_MsgTypeDef MB_REQUEST_RETURN_BUS_CHARACTER_OVERRUN_COUNT(uint8_t slave_addr); + +//---------ИДЕНТИФИКАТОРЫ МОДБАС----------- +RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_BASIC(uint8_t slave_addr); +RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_REGULAR(uint8_t slave_addr); +RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_EXTENDED(uint8_t slave_addr); +RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_SPECIFIC(uint8_t slave_addr, uint8_t object_id); +/** MODBUS_REQUEST_MSG + * @} + */ + + +/** + * @addtogroup MODBUS_REGS_API API for Registers + * @ingroup MODBUS_REQUEST_MSG + * @brief API для чтения регистров из ответа в режиме мастер + * @details Примеры использования: + * + * @code + * // Пример: Запросили 10 регистров с адреса 100, хотим получить значение регистра 105 + * uint16_t reg_value; + * if(MB_GetRegisterValue(&MODBUS_MSG, 105, ®_value)) + * { + * printf("Register 105 value: %d\n", reg_value); + * } + * + * // Пример: Получить все запрошенные регистры + * for(int addr = MODBUS_MSG.Addr; addr < MODBUS_MSG.Addr + MODBUS_MSG.Qnt; addr++) + * { + * uint16_t value; + * if(MB_GetRegisterValue(&MODBUS_MSG, addr, &value)) + * { + * printf("Register %d: %d\n", addr, value); + * } + * } + * @endcode + */ + +int MB_GetRegisterValue(RS_MsgTypeDef *modbus_msg, uint16_t reg_addr, uint16_t *reg_value); + + +/** MODBUS_REQ_REGS_API + * @} + */ + + +/* Сбор сообщения в буфер UART в режиме мастер (фрейм мастера из msg -> uart) */ +RS_StatusTypeDef MB_Master_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff); +/* Парс сообщения в режиме мастер (фрейм слейва из uart -> msg) */ +RS_StatusTypeDef MB_Master_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff); + + +#endif //__MODBUS_MASTER_H_ + +/** MODBUS_MASTER + * @} + */ \ No newline at end of file diff --git a/Modbus/Inc/modbus_slave.h b/Modbus/Inc/modbus_slave.h new file mode 100644 index 0000000..810d7ef --- /dev/null +++ b/Modbus/Inc/modbus_slave.h @@ -0,0 +1,34 @@ +/** +****************************************************************************** +* @file modbus_slave.h +* @brief Главный заголовочный файл Modbus библиотеки +****************************************************************************** +@addtogroup MODBUS_SLAVE Modbus slave funtions +@ingroup MODBUS_CMD_PROCESS_FUNCTIONS +@{ +****************************************************************************** +* @details +Модуль реализации обработки UART сообщение в режиме слейв +******************************************************************************/ +#ifndef __MODBUS_SLAVE_H_ +#define __MODBUS_SLAVE_H_ + +#include "rs_message.h" + + +#ifdef MODBUS_ENABLE_SLAVE +#define MODBUS_MODE_SLAVE 0 +#endif + +/* Ответ на сообщение в режиме слейва */ +RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg); +/* Сбор сообщения в буфер UART в режиме слейв (фрейм слейва из msg -> uart) */ +RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff); +/* Парс сообщения в режиме слейв (фрейм мастера из uart -> msg) */ +RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff); + +#endif //__MODBUS_SLAVE_H_ + +/** MODBUS_MASTER + * @} + */ \ No newline at end of file diff --git a/Modbus/Inc/rs_message.h b/Modbus/Inc/rs_message.h index 994d532..98b9ea5 100644 --- a/Modbus/Inc/rs_message.h +++ b/Modbus/Inc/rs_message.h @@ -40,10 +40,6 @@ #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 Заглушки и внутренний недокументированный стаф */ @@ -55,14 +51,14 @@ #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_Flags(_hRS_) _hRS_->f.RX_Busy = 1; _hRS_->f.RX_Done = 0; #define RS_Set_RX_Active_Flags(_hRS_) _hRS_->f.RX_Ongoing = 1 #define RS_Set_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_RX_Active_Flags(_hRS_) _hRS_->f.RX_Ongoing = 0; _hRS_->f.RX_Continue = 0; +#define RS_Reset_RX_Flags(_hRS_) RS_Reset_RX_Active_Flags(_hRS_); _hRS_->f.RX_Busy = 0; _hRS_->f.RX_Done = 0; #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; @@ -79,15 +75,16 @@ #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() + +#ifndef printf_rs_err +#define printf_rs_err(...) #endif -#ifndef __MYLIBS_INCLUDE_H_ +#ifndef printf_rs +#define printf_rs(...) +#endif + +#ifndef __MYLIBS_CONFIG_H_ // дефайны из mylibs include static int dummy; #define TrackerTypeDef(num_user_vars) void * @@ -110,20 +107,24 @@ static int dummy; #define TrackerClear_Warn(_cntstruct_) #define TrackerClear_User(_cntstruct_) #define TrackerClear_UserAll(_cntstruct_) - -#ifndef printf_rs_err -#define printf_rs_err(...) +#else +#include "mylibs_include.h" #endif -#ifndef printf_rs -#define printf_rs(...) -#endif -#endif #ifndef RS_USER_VARS_NUMB #define RS_USER_VARS_NUMB 0 #endif /** @endcond */ + + +// направление передачи rs485 +#ifndef RS_EnableReceive +#define RS_EnableReceive() ///< Функция изменения направления передачи на ПРИЕМ для RS-485 +#endif +#ifndef RS_EnableTransmit +#define RS_EnableTransmit() ///< Функция изменения направления передачи на ПЕРЕДАЧУ для RS-485 +#endif ////////////////////////////---DEFINES---//////////////////////////// @@ -149,61 +150,44 @@ typedef enum // RS_StatusTypeDef }RS_StatusTypeDef; -#define RS_MASTER_START 0x3 +#define RS_MASTER_MODE_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_SLAVE_ALWAYS_WAIT = 0x01, ///< Слейв в постоянном ожидании + RS_RESERVED = 0x02, ///< резерв + RS_MASTER_REQUEST = 0x03, ///< Мастер с ручным запросом + //RS_MASTER_POLLING = 0x04, ///< Мастер с опросом в фоновом режиме }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 + ABORT_TX = 0x01, ///< Отменить передачу + ABORT_RX = 0x02, ///< Отменить прием + ABORT_RX_TX = 0x03, ///< Отменить прием и передачу + ABORT_RS = 0x04, ///< Отменить любую работу UART в целом }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; ///< 1 - RS занят, 0 - RS свободен + unsigned RX_Ongoing:1; ///< 1 - Прием данных в активном состоянии, 0 - Ожидаем начало приема данных - unsigned RS_Busy:1; ///< flag: 1 - RS is busy, 0 - RS isnt busy - unsigned RX_Ongoing:1; ///< flag: 1 - receiving data right now, 0 - waiting for receiving data + unsigned RX_Busy:1; ///< 1 - Режим приема активен, 0 - Прием не активен + unsigned TX_Busy:1; ///< 1 - Режим передачи активен, 0 - Прием не активен - 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 + unsigned RX_Done:1; ///< 1 - Прием закончен, 0 - Прием еще в процессе или не инициализирован + unsigned TX_Done:1; ///< 1 - Передача закончена, 0 - Передача еще в процессе или не инициализирована - // 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 + // Выставление следующие флагов определяет пользователь + unsigned RX_Continue:1; ///< 0 - Продолжить принимать, 0 - Начать прием сначала + unsigned MessageHandled:1; ///< 1 - Обработка запроса успешна, 0 - Обработка запроса в процессе или ошибка + unsigned EchoResponse:1; ///< 1 - Ответить эхом, 0 - Ответить своим сообщением + unsigned DeferredResponse:1; ///< 1 - Не начинать передачу в IT, 0 - Ответить в прерывании + unsigned DataUpdated:1; ///< 1 - Данные были обновлены }RS_FlagsTypeDef; @@ -215,25 +199,24 @@ typedef struct 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 + uint8_t ID; ///< ID хендла + RS_MsgTypeDef *pMessagePtr; ///< Указатель на структуру протокола + uint8_t *pBufferPtr; ///< Указатеь на буфер UART 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 + UART_HandleTypeDef *huart; ///< Хендл UART + TIM_HandleTypeDef *htim; ///< Хендл TIM + RS_ModeTypeDef sRS_Mode; ///< Настройка: слейв/мастер @ref RS_ModeTypeDef + uint16_t sRS_Timeout; ///< Настройка: Таймаут в тиках таймера + void (*pCallback)(void*, void*); ///< Указатель на коллбек: принят ответ в режиме мастер /* FLAGS */ - RS_FlagsTypeDef f; ///< These flags for controling receive/transmit + RS_FlagsTypeDef f; ///< Флаги для контроля приема/передачи /* RS STATUS */ - uint32_t lastPacketTick; - RS_StatusTypeDef RS_STATUS; ///< RS status + uint32_t lastPacketTick; ///< Время последнего принятого пакета + RS_StatusTypeDef RS_STATUS; ///< Статус RS TrackerTypeDef(RS_USER_VARS_NUMB) rs_err; }RS_HandleTypeDef; @@ -247,47 +230,53 @@ extern RS_HandleTypeDef hmodbus1; ///////////////////////////---FUNCTIONS---/////////////////////////// //----------------FUNCTIONS FOR PROCESSING MESSAGE------------------- /*--------------------Defined by users purposes--------------------*/ -/* Respond accord to received message */ +/* Пользовательская функция для ответа на запрос по UART */ RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg); -/* Collect message in buffer to transmit it */ +/* Пользовательская функция для обработки принятого ответа по UART */ +__weak RS_StatusTypeDef RS_Response_Callback(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg); + +/* Пользовательская функция для сбора сообщения в буфер UART */ RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff); -/* Parse message from buffer to process it */ +/* Пользовательская функция для парса сообщения из буфера UART */ RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff); //-------------------------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 */ +/* Инициалазация структуры @ref RS_HandleTypeDef */ 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/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 */ +/* UART TX Callback: коллбек после окончания передачи */ RS_StatusTypeDef RS_UART_TxCpltCallback(RS_HandleTypeDef *hRS); -/* Handler for UART */ +/* Обработчик прерывания UART */ void RS_UART_Handler(RS_HandleTypeDef *hRS); -/* Handler for TIM */ +/* Обработчик прерывания TIM */ void RS_TIM_Handler(RS_HandleTypeDef *hRS); +/* Запуск таймаута приема. */ +RS_StatusTypeDef RS_Timeout_Start(RS_HandleTypeDef *hRS); +/* Остановка таймаута приема. */ +RS_StatusTypeDef RS_Timeout_Stop(RS_HandleTypeDef *hRS); +/* Обновление (сброс) таймаута приема. */ +RS_StatusTypeDef RS_Timeout_Update(RS_HandleTypeDef *hRS); //--------------------CALLBACK/HANDLER FUNCTIONS--------------------- ///////////////////////////---FUNCTIONS---/////////////////////////// diff --git a/Modbus/Src/modbus.c b/Modbus/Src/modbus.c index a5aad72..a39cf08 100644 --- a/Modbus/Src/modbus.c +++ b/Modbus/Src/modbus.c @@ -9,58 +9,58 @@ @section Функции и макросы ### Инициализация: -- MODBUS_SetupHardware() — Инициализация модуля Modbus. -- MODBUS_Config() — Инициализация модуля Modbus. - -### Функции для Modbus -- MB_Slave_Response() -- MB_Slave_Collect_Message() -- MB_Slave_Parse_Message() -- MB_Master_Collect_Message() -- MB_Master_Parse_Message() +- MODBUS_FirstInit() — Инициализация Modbus (подключение UART, TIM) +- MODBUS_Config() — Конфигурацмя Modbus (ID, Timeout). +- MODBUS_SlaveStart() — Запуск Modbus как Slave. +- MODBUS_MasterRequest() — Отправить запрос в MODBUS как Master. ### Функции для работы с RS (UART): - RS_Parse_Message() / RS_Collect_Message() — Парсинг и сборка сообщения. - RS_Response() — Отправка ответа. - ******************************************************************************/ - #include "modbus.h" /* MODBUS HANDLES */ -RS_HandleTypeDef hmodbus1; -RS_MsgTypeDef MODBUS_MSG; +RS_HandleTypeDef hmodbus1; ///< Default Handle for Modbus +RS_MsgTypeDef MODBUS_MSG; ///< Default Message Struct for Modbus -/* DEFINE REGISTERS/COILS */ -MB_DeviceIdentificationTypeDef MB_DEVID; -MB_DataStructureTypeDef MB_DATA = {0};; +/* DEFINE DATA FOR MODBUS */ +MB_DataStructureTypeDef MB_DATA = {0};; ///< Coils & Registers + +static void MB_DefaultCallback(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg); //------------------------------------------------------------------- //-----------------------------FOR USER------------------------------ /** * @brief Инициализация периферии модбас. * @param hmodbus Указатель на хендлер RS + * @param huart Указатель на хендлер UART + * @param htim Указатель на хендлер TIM * @details Подключает хендлы периферии к hmodbus * Конфигурация выставляется по умолчанию из modbus_config.h */ -void MODBUS_SetupHardware(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim) +HAL_StatusTypeDef MODBUS_FirstInit(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim) { if((hmodbus == NULL) || (huart == NULL)) { - return; + return HAL_ERROR; } MB_DeviceInentificationInit(); //-----------SETUP MODBUS------------- // set up modbus: MB_RX_Size_NotConst and Timeout enable - hmodbus1.ID = MODBUS_DEVICE_ID; - hmodbus1.sRS_Timeout = MODBUS_TIMEOUT; - hmodbus1.sRS_Mode = RS_SLAVE_ALWAYS_WAIT; - hmodbus1.sRS_RX_Size_Mode = RS_RX_Size_NotConst; + hmodbus->ID = MODBUS_DEVICE_ID; + hmodbus->sRS_Timeout = MODBUS_TIMEOUT; + hmodbus->sRS_Mode = RS_SLAVE_ALWAYS_WAIT; // INIT - hmodbus1.RS_STATUS = RS_Init(hmodbus, huart, htim, 0); + hmodbus->RS_STATUS = RS_Init(hmodbus, huart, htim, 0); RS_EnableReceive(); + + if(hmodbus->RS_STATUS == RS_OK) + return HAL_OK; + else + return HAL_ERROR; } /** * @brief Программная конфигурация модбас. @@ -69,460 +69,115 @@ void MODBUS_SetupHardware(RS_HandleTypeDef *hmodbus, UART_HandleTypeDef *huart, * @param master Режим мастер (пока не сделан) * @details Конфигурирует ID, таймаут и режим hmodbus */ -void MODBUS_Config(RS_HandleTypeDef *hmodbus, uint8_t ID, uint16_t Timeout, uint8_t master) +HAL_StatusTypeDef MODBUS_Config(RS_HandleTypeDef *hmodbus, uint8_t ID, uint16_t Timeout, uint8_t master) { if(hmodbus == NULL) { - return; + return HAL_ERROR; } - //-----------SETUP MODBUS------------- - // set up modbus: MB_RX_Size_NotConst and Timeout enable - hmodbus->ID = ID; + if(!master) + { + if((ID < 1) || (ID > 247)) + { + return HAL_ERROR; + } + hmodbus->ID = ID; + } + else + hmodbus->ID = 0; + hmodbus->sRS_Timeout = Timeout; if(master) - hmodbus->sRS_Mode = RS_SLAVE_ALWAYS_WAIT; + hmodbus->sRS_Mode = RS_MASTER_REQUEST; else hmodbus->sRS_Mode = RS_SLAVE_ALWAYS_WAIT; - hmodbus->sRS_RX_Size_Mode = RS_RX_Size_NotConst; + + return HAL_OK; } /** * @brief Запуск слейв модбас. * @param hmodbus Указатель на хендлер RS. - * @param modbus_msg Указатель на структуру сообщения. + * @param modbus_msg Указатель на структуру сообщения. + (NULL чтобы использовать дефолтную) * @details Конфигурирует ID, таймаут и режим hmodbus */ -void MODBUS_SlaveStart(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) +HAL_StatusTypeDef MODBUS_SlaveStart(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) { if(hmodbus == NULL) { - return; + return HAL_ERROR; } + if(hmodbus->sRS_Mode >= RS_MASTER_MODE_START) + { + return HAL_ERROR; + } + + MB_DiagnosticsInit(); + if(modbus_msg) - RS_Receive_IT(hmodbus, modbus_msg); + hmodbus->RS_STATUS = RS_Receive_IT(hmodbus, modbus_msg); else - RS_Receive_IT(hmodbus, &MODBUS_MSG); + hmodbus->RS_STATUS = RS_Receive_IT(hmodbus, &MODBUS_MSG); + + if(hmodbus->RS_STATUS == RS_OK) + return HAL_OK; + else + return HAL_ERROR; } - - - /** - * @brief Ответ на сообщение в режиме слейва. + * @brief Реквест мастера модбас. * @param hmodbus Указатель на хендлер RS. - * @param modbus_msg Указатель на структуру сообщения. - * @return RS_RES Статус о результате ответа на комманду. + * @param modbus_msg Указатель на структуру сообщения + * @details Конфигурирует ID, таймаут и режим hmodbus */ -static RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) +HAL_StatusTypeDef MODBUS_MasterRequest(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, void (*pClbk)(RS_HandleTypeDef*, RS_MsgTypeDef*)) { - RS_StatusTypeDef MB_RES = 0; - hmodbus->f.MessageHandled = 0; - hmodbus->f.EchoResponse = 0; - RS_Reset_TX_Flags(hmodbus); // reset flag for correct transmit - - if(hmodbus->ID == 0) + if(hmodbus == NULL) { - hmodbus->RS_STATUS = RS_SKIP; - return MB_RES; + return HAL_ERROR; } - - if(modbus_msg->Func_Code < ERR_VALUES_START)// if no errors after parsing + if(modbus_msg == NULL) { - switch (modbus_msg->Func_Code) - { - // Read Coils - case MB_R_COILS: - hmodbus->f.MessageHandled = MB_Proccess_Read_Coils(hmodbus->pMessagePtr); - break; - - // Read Hodling Registers - case MB_R_HOLD_REGS: - hmodbus->f.MessageHandled = MB_Proccess_Read_Hold_Regs(hmodbus->pMessagePtr); - break; - case MB_R_IN_REGS: - hmodbus->f.MessageHandled = MB_Proccess_Read_Input_Regs(hmodbus->pMessagePtr); - break; - - - // Write Single Coils - case MB_W_COIL: - hmodbus->f.MessageHandled = MB_Proccess_Write_Single_Coil(hmodbus->pMessagePtr); - if(hmodbus->f.MessageHandled) - { - hmodbus->f.DataUpdated = 1; - hmodbus->f.EchoResponse = 1; - hmodbus->RS_Message_Size -= 2; // echo response if write ok (minus 2 cause of two CRC bytes) - } - break; - - case MB_W_HOLD_REG: - hmodbus->f.MessageHandled = MB_Proccess_Write_Single_Reg(hmodbus->pMessagePtr); - if(hmodbus->f.MessageHandled) - { - hmodbus->f.DataUpdated = 1; - hmodbus->f.EchoResponse = 1; - hmodbus->RS_Message_Size -= 2; // echo response if write ok (minus 2 cause of two CRC bytes) - } - break; - - // Write Multiple Coils - case MB_W_COILS: - hmodbus->f.MessageHandled = MB_Write_Miltuple_Coils(hmodbus->pMessagePtr); - if(hmodbus->f.MessageHandled) - { - hmodbus->f.DataUpdated = 1; - hmodbus->f.EchoResponse = 1; - hmodbus->RS_Message_Size = 6; // echo response if write ok (withous data bytes) - } - break; - - // Write Multiple Registers - case MB_W_HOLD_REGS: - hmodbus->f.MessageHandled = MB_Proccess_Write_Miltuple_Regs(hmodbus->pMessagePtr); - if(hmodbus->f.MessageHandled) - { - hmodbus->f.DataUpdated = 1; - hmodbus->f.EchoResponse = 1; - hmodbus->RS_Message_Size = 6; // echo response if write ok (withous data bytes) - } - break; - - case MB_R_DEVICE_INFO: - hmodbus->f.MessageHandled = MB_Proccess_Read_Device_Identification(hmodbus->pMessagePtr); - break; - - /* unknown func code */ - default: modbus_msg->Except_Code = 0x01; /* set exception code: illegal function */ - } - - if(hmodbus->f.MessageHandled == 0) - { - TrackerCnt_Warn(hmodbus->rs_err); - modbus_msg->Func_Code |= ERR_VALUES_START; - } - else - { - TrackerCnt_Ok(hmodbus->rs_err); - } - - + return HAL_ERROR; + } + if(hmodbus->sRS_Mode < RS_MASTER_MODE_START) + { + return HAL_ERROR; } - // if we need response - check that transmit isnt busy - if( RS_Is_TX_Busy(hmodbus) ) - RS_Abort(hmodbus, ABORT_TX); // if tx busy - set it free + if(hmodbus->f.RS_Busy) + return HAL_BUSY; + + if(pClbk) // если задан используем пользовательский коллбек + hmodbus->pCallback = (void (*)(void*, void*))(pClbk); + else // иначе дефолтный + hmodbus->pCallback = (void (*)(void*, void*))(&MB_DefaultCallback); - // Transmit right there, or sets (fDeferredResponse) to transmit response in main code - if(hmodbus->f.DeferredResponse == 0) - { - MB_RES = RS_Handle_Transmit_Start(hmodbus, modbus_msg); - } + hmodbus->RS_STATUS = RS_Transmit_IT(hmodbus, modbus_msg); + + if(hmodbus->RS_STATUS == RS_OK) + return HAL_OK; else - { - RS_Handle_Receive_Start(hmodbus, modbus_msg); - hmodbus->f.DeferredResponse = 0; - } - - hmodbus->RS_STATUS = MB_RES; - return MB_RES; + return HAL_ERROR; } -/** - * @brief Сбор сообщения в буфер UART в режиме слейв. - * @param hmodbus Указатель на хендлер RS. - * @param modbus_msg Указатель на структуру сообщения. - * @param modbus_uart_buff Указатель на буффер UART. - * @return RS_RES Статус о результате заполнения буфера. - */ -static RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff) + +static void MB_DefaultCallback(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) { - int ind = 0; // ind for modbus-uart buffer - - if(hmodbus->f.EchoResponse && hmodbus->f.MessageHandled) // if echo response need - ind = hmodbus->RS_Message_Size; - else - { - //------INFO ABOUT DATA/MESSAGE------ - //-----------[first bytes]----------- - // set ID of message/user - modbus_uart_buff[ind++] = modbus_msg->MbAddr; - - // set dat or err response - modbus_uart_buff[ind++] = modbus_msg->Func_Code; - - if (modbus_msg->Func_Code < ERR_VALUES_START) // if no error occur - { - // fill modbus header - if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) // devide identification header - { - modbus_uart_buff[ind++] = modbus_msg->DevId.MEI_Type; - modbus_uart_buff[ind++] = modbus_msg->DevId.ReadDevId; - modbus_uart_buff[ind++] = modbus_msg->DevId.Conformity; - modbus_uart_buff[ind++] = modbus_msg->DevId.MoreFollows; - modbus_uart_buff[ind++] = modbus_msg->DevId.NextObjId; - modbus_uart_buff[ind++] = modbus_msg->DevId.NumbOfObj; - - if (modbus_msg->ByteCnt > DATA_SIZE*2) // if ByteCnt less than DATA_SIZE - { - TrackerCnt_Err(hmodbus->rs_err); - return RS_COLLECT_MSG_ERR; - } - - - //---------------DATA---------------- - //-----------[data bytes]------------ - uint8_t *tmp_data_addr = (uint8_t *)modbus_msg->DATA; - for(int i = 0; i < modbus_msg->ByteCnt; i++) // filling buffer with data - { // set data - modbus_uart_buff[ind++] = *tmp_data_addr; - tmp_data_addr++; - } - - } - else // modbus data header - { - // set size of received data - if (modbus_msg->ByteCnt <= DATA_SIZE*2) // if ByteCnt less than DATA_SIZE - modbus_uart_buff[ind++] = modbus_msg->ByteCnt; - else // otherwise return data_size err - { - TrackerCnt_Err(hmodbus->rs_err); - return RS_COLLECT_MSG_ERR; - } - - //---------------DATA---------------- - //-----------[data bytes]------------ - uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->DATA; - for(int i = 0; i < modbus_msg->ByteCnt; i++) // filling buffer with data - { // set data - if (i%2 == 0) // HI byte - modbus_uart_buff[ind++] = (*tmp_data_addr)>>8; - else // LO byte - { - modbus_uart_buff[ind++] = *tmp_data_addr; - tmp_data_addr++; - } - } - - } - - } - else // if some error occur - { // send expection code - modbus_uart_buff[ind++] = modbus_msg->Except_Code; - } - } - if(ind < 0) - return RS_COLLECT_MSG_ERR; - - //---------------CRC---------------- - //---------[last 16 bytes]---------- - // calc crc of received data - uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind); - // write crc to message structure and modbus-uart buffer - modbus_msg->MB_CRC = CRC_VALUE; - modbus_uart_buff[ind++] = CRC_VALUE; - modbus_uart_buff[ind++] = CRC_VALUE >> 8; - - hmodbus->RS_Message_Size = ind; - - return RS_OK; // returns ok + __NOP(); + return; } -/** - * @brief Определить размер модбас запроса. - * @param hRS Указатель на хендлер RS. - * @param rx_data_size Указатель на переменную для записи кол-ва байт для принятия. - * @return RS_RES Статус о корректности рассчета кол-ва байт для принятия. - * @details Определение сколько байтов надо принять по протоколу. - */ -static int MB_Define_Size_of_Function(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) -{ - RS_StatusTypeDef MB_RES = 0; - int mb_func_size = 0; - - if ((modbus_msg->Func_Code & ~ERR_VALUES_START) < 0x0F) - { - modbus_msg->ByteCnt = 0; - mb_func_size = 1; - - } - else - { - modbus_msg->ByteCnt = hmodbus->pBufferPtr[RX_FIRST_PART_SIZE-1]; // get numb of data in command - // +1 because that defines is size, not ind. - mb_func_size = modbus_msg->ByteCnt + 2; - } - - - if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) - { - mb_func_size = 0; - } - - mb_func_size = RX_FIRST_PART_SIZE + mb_func_size; // size of whole message - return mb_func_size; -} - - -/** - * @brief Парс сообщения в режиме слейв. - * @param hmodbus Указатель на хендлер RS. - * @param modbus_msg Указатель на структуру сообщения. - * @param modbus_uart_buff Указатель на буффер UART. - * @return RS_RES Статус о результате заполнения структуры. - * @details Заполнение структуры сообщения из буффера UART. - */ -static RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff) -{ - uint32_t check_empty_buff; - int ind = 0; // ind for modbus-uart buffer - hmodbus->f.RX_Continue = 0; - //-----INFO ABOUT DATA/MESSAGE------- - //-----------[first bits]------------ - // get ID of message/user - if(modbus_uart_buff[ind] != hmodbus->ID) - { - modbus_msg->MbAddr = 0; - return RS_SKIP; - } - modbus_msg->MbAddr = modbus_uart_buff[ind++]; - - // get func code - modbus_msg->Func_Code = modbus_uart_buff[ind++]; - if(modbus_msg->Func_Code & ERR_VALUES_START) // явная херня - { - modbus_msg->MbAddr = 0; - return RS_SKIP; - } - - if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) // if it device identification request - { - modbus_msg->DevId.MEI_Type = modbus_uart_buff[ind++]; - modbus_msg->DevId.ReadDevId = modbus_uart_buff[ind++]; - modbus_msg->DevId.NextObjId = modbus_uart_buff[ind++]; - modbus_msg->ByteCnt = 0; - } - else // if its classic modbus request - { - // get address from CMD - modbus_msg->Addr = modbus_uart_buff[ind++] << 8; - modbus_msg->Addr |= modbus_uart_buff[ind++]; - - // get address from CMD - modbus_msg->Qnt = modbus_uart_buff[ind++] << 8; - modbus_msg->Qnt |= modbus_uart_buff[ind++]; - } - - if((hmodbus->pMessagePtr->Func_Code == 0x0F) || (hmodbus->pMessagePtr->Func_Code == 0x10)) - hmodbus->pMessagePtr->ByteCnt = modbus_uart_buff[ind++]; - else - hmodbus->pMessagePtr->ByteCnt = 0; - - //---------------DATA---------------- - // (optional) - if (modbus_msg->ByteCnt != 0) - { - //check that data size is correct - if (modbus_msg->ByteCnt > DATA_SIZE*2) - { - TrackerCnt_Err(hmodbus->rs_err); - modbus_msg->Func_Code |= ERR_VALUES_START; - return RS_PARSE_MSG_ERR; - } - uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->DATA; - for(int i = 0; i < modbus_msg->ByteCnt; i++) - { // set data - if (i%2 == 0) - *tmp_data_addr = ((uint16_t)modbus_uart_buff[ind++] << 8); - else - { - *tmp_data_addr |= modbus_uart_buff[ind++]; - tmp_data_addr++; - } - } - } - - //---------------CRC---------------- - //----------[last 16 bits]---------- - // calc crc of received data - uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind); - // get crc of received data - modbus_msg->MB_CRC = modbus_uart_buff[ind++]; - modbus_msg->MB_CRC |= modbus_uart_buff[ind++] << 8; - // compare crc - if (modbus_msg->MB_CRC != CRC_VALUE) - { - TrackerCnt_Err(hmodbus->rs_err); - modbus_msg->Func_Code |= ERR_VALUES_START; - } -// hmodbus->MB_RESPONSE = MB_CRC_ERR; // set func code - error about wrong crc - - // check is buffer empty - check_empty_buff = 0; - for(int i=0; iMB_RESPONSE = MB_EMPTY_MSG; // - - // если размер меньше ожидаемого - продолжаем принимать - if(hmodbus->RS_Message_Size < MB_Define_Size_of_Function(hmodbus, modbus_msg)) - { - hmodbus->f.RX_Continue = 1; - return RS_SKIP; - } - // если больше Ошибка - else if (hmodbus->RS_Message_Size > MB_Define_Size_of_Function(hmodbus, modbus_msg)) - { - return RS_PARSE_MSG_ERR; - } - - return RS_OK; -} - - - - - - - - -/** - * @brief Сбор сообщения в буфер UART в режиме мастер. - * @param hmodbus Указатель на хендлер RS. - * @param modbus_msg Указатель на структуру сообщения. - * @param modbus_uart_buff Указатель на буффер UART. - * @return RS_RES Статус о результате заполнения буфера. - */ -static RS_StatusTypeDef MB_Master_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff) -{ - return RS_PARSE_MSG_ERR; -} - - -/** - * @brief Парс сообщения в режиме мастер. - * @param hmodbus Указатель на хендлер RS. - * @param modbus_msg Указатель на структуру сообщения. - * @param modbus_uart_buff Указатель на буффер UART. - * @return RS_RES Статус о результате заполнения структуры. - */ -static RS_StatusTypeDef MB_Master_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff) -{ - return RS_PARSE_MSG_ERR; -} - - - - /* Реализация функций из rs_message.c для протокола */ RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) { - if(hmodbus->sRS_Mode >= RS_MASTER_START) + if(hmodbus->sRS_Mode >= RS_MASTER_MODE_START) { return RS_ERR; } @@ -531,7 +186,7 @@ RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_ms RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff) { - if(hmodbus->sRS_Mode < RS_MASTER_START) + if(hmodbus->sRS_Mode < RS_MASTER_MODE_START) { return MB_Slave_Collect_Message(hmodbus, modbus_msg, modbus_uart_buff); } @@ -543,7 +198,7 @@ RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *mo RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff) { - if(hmodbus->sRS_Mode < RS_MASTER_START) + if(hmodbus->sRS_Mode < RS_MASTER_MODE_START) { return MB_Slave_Parse_Message(hmodbus, modbus_msg, modbus_uart_buff); } diff --git a/Modbus/Src/modbus_coils.c b/Modbus/Src/modbus_coils.c index f0dd07e..8c629a9 100644 --- a/Modbus/Src/modbus_coils.c +++ b/Modbus/Src/modbus_coils.c @@ -12,10 +12,10 @@ ******************************************************************************/ #include "modbus_coils.h" - +#ifdef MODBUS_ENABLE_COILS /** - * @brief Set or Reset Coil at its global address. + * @brief Выставить/сбросить коил по глобальному адресу. * @param Addr Адрес коила. * @param WriteVal Что записать в коил: 0 или 1. * @return ExceptionCode Код исключения если коила по адресу не существует, и NO_ERRORS если все ок. @@ -55,7 +55,7 @@ MB_ExceptionTypeDef MB_Write_Coil_Global(uint16_t Addr, MB_CoilsOpTypeDef WriteV /** - * @brief Read Coil at its global address. + * @brief Считать коил по глобальному адресу. * @param Addr Адрес коила. * @param Exception Указатель на переменную для кода исключения, в случа неудачи при чтении. * @return uint16_t Возвращает весь регистр с маской на запрошенном коиле. @@ -86,13 +86,48 @@ uint16_t MB_Read_Coil_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception) } -/** - * @brief Proccess command Read Coils (01 - 0x01). + +/** + * @brief Получить состояние coil в ответе по его адресу + * @param modbus_msg Указатель на структуру сообщения + * @param coil_addr Адрес coil, состояние которого нужно получить + * @param coil_state Указатель для состояния coil (1 - ON, 0 - OFF) + * @return 1 - успех, 0 - ошибка или coil_addr вне диапазона запроса + */ +int MB_GetCoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coil_state) +{ + if(modbus_msg == NULL || coil_state == NULL) + 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 bit_index = coil_index % 8; + + // Проверяем что байт существует в данных + if(byte_index >= modbus_msg->ByteCnt) + return 0; + + // Получаем байт и проверяем бит + uint8_t coil_byte = modbus_msg->DATA[byte_index] & 0xFF; + *coil_state = (coil_byte >> bit_index) & 0x01; + + return 1; +} + +/** + * @brief Обработать функцию Read Coils (01 - 0x01). * @param modbus_msg Указатель на структуру собщения modbus. * @return fMessageHandled Статус о результате обработки комманды. * @details Обработка команды Read Coils. */ -uint8_t MB_Proccess_Read_Coils(RS_MsgTypeDef *modbus_msg) +uint8_t MB_Process_Read_Coils(RS_MsgTypeDef *modbus_msg) { //---------CHECK FOR ERRORS---------- uint16_t *coils; @@ -140,12 +175,12 @@ uint8_t MB_Proccess_Read_Coils(RS_MsgTypeDef *modbus_msg) } /** - * @brief Proccess command Write Single Coils (05 - 0x05). + * @brief Обработать функцию Write Single Coils (05 - 0x05). * @param modbus_msg Указатель на структуру собщения modbus. * @return fMessageHandled Статус о результате обработки комманды. * @details Обработка команды Write Single Coils. */ -uint8_t MB_Proccess_Write_Single_Coil(RS_MsgTypeDef *modbus_msg) +uint8_t MB_Process_Write_Single_Coil(RS_MsgTypeDef *modbus_msg) { //---------CHECK FOR ERRORS---------- if ((modbus_msg->Qnt != 0x0000) && (modbus_msg->Qnt != 0xFF00)) @@ -171,7 +206,7 @@ uint8_t MB_Proccess_Write_Single_Coil(RS_MsgTypeDef *modbus_msg) } /** - * @brief Proccess command Write Multiple Coils (15 - 0x0F). + * @brief Обработать функцию Write Multiple Coils (15 - 0x0F). * @param modbus_msg Указатель на структуру собщения modbus. * @return fMessageHandled Статус о результате обработки комманды. * @details Обработка команды Write Multiple Coils. @@ -236,3 +271,14 @@ uint8_t MB_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg) return 1; } +#else //MODBUS_ENABLE_COILS + + +int MB_GetCoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coil_state) {return 0;} +MB_ExceptionTypeDef MB_Write_Coil_Global(uint16_t Addr, MB_CoilsOpTypeDef WriteVal) {return ILLEGAL_FUNCTION;} +uint16_t MB_Read_Coil_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_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg) {return 0;} + +#endif \ No newline at end of file diff --git a/Modbus/Src/modbus_data.c b/Modbus/Src/modbus_data.c index a9b49ae..5537991 100644 --- a/Modbus/Src/modbus_data.c +++ b/Modbus/Src/modbus_data.c @@ -77,7 +77,7 @@ MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, u // Default holding registers if(MB_Check_Address_For_Arr(Addr, Qnt, R_HOLDING_ADDR, R_HOLDING_QNT) == NO_ERRORS) { - *pRegs = MB_Set_Register_Ptr(&MB_DATA.HoldRegs, Addr); // указатель на выбранный по Addr регистр + *pRegs = MB_Set_Register_Ptr(&MB_DATA.HoldRegs, Addr - R_HOLDING_ADDR); // указатель на выбранный по Addr регистр } // if address doesnt match any array - return illegal data address response else @@ -90,7 +90,7 @@ MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, u // Default input registers if(MB_Check_Address_For_Arr(Addr, Qnt, R_INPUT_ADDR, R_INPUT_QNT) == NO_ERRORS) { - *pRegs = MB_Set_Register_Ptr(&MB_DATA.InRegs, Addr); // указатель на выбранный по Addr регистр + *pRegs = MB_Set_Register_Ptr(&MB_DATA.InRegs, Addr - R_INPUT_ADDR); // указатель на выбранный по Addr регистр } // if address doesnt match any array - return illegal data address response else @@ -128,7 +128,7 @@ MB_ExceptionTypeDef MB_DefineCoilsAddress(uint16_t **pCoils, uint16_t Addr, uint // Default coils if(MB_Check_Address_For_Arr(Addr, Qnt, C_COILS_ADDR, C_COILS_QNT) == NO_ERRORS) { - *pCoils = MB_Set_Coil_Reg_Ptr(&MB_DATA.Coils, Addr); // указатель на выбранный по Addr массив коилов + *pCoils = MB_Set_Coil_Reg_Ptr(&MB_DATA.Coils, Addr - C_COILS_ADDR); // указатель на выбранный по Addr массив коилов } // if address doesnt match any array - return illegal data address response else diff --git a/Modbus/Src/modbus_devid.c b/Modbus/Src/modbus_devid.c index 31829aa..9d08bfb 100644 --- a/Modbus/Src/modbus_devid.c +++ b/Modbus/Src/modbus_devid.c @@ -1,7 +1,7 @@ /** ****************************************************************************** * @file modbus_devid.c -* @brief Реализация идентификации устройства Modbus +* @brief Реализация идентификаторов устройства Modbus ****************************************************************************** * @details Модуль обработки запросов идентификации устройства через MEI-тип 0x0E: @@ -14,15 +14,124 @@ сообщений с установкой флага MoreFollows и указанием NextObjId для продолжения чтения в следующем запросе. ******************************************************************************/ - #include "modbus_devid.h" +#ifdef MODBUS_ENABLE_DEVICE_IDENTIFICATIONS + +MB_DeviceIdentificationsTypeDef MB_DEVID; ///< Глобальная структура идентификаторов устройства + + +/** + * @brief Получить количество объектов в сообщении + * @param modbus_msg Указатель на структуру сообщения + * @return int Количество объектов + */ +int MB_GetNumberOfObjects(RS_MsgTypeDef *modbus_msg) +{ + 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_FindObjectById(RS_MsgTypeDef *modbus_msg, uint8_t obj_id, char *obj_data, uint8_t *obj_length) +{ + if((modbus_msg == NULL) || (obj_data == NULL)) + 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_GetObjectByIndex(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(index >= modbus_msg->DevId.NumbOfObj) + return 0; + + uint8_t *data = (uint8_t*)modbus_msg->DATA; + unsigned ind = 0; + + for(int i = 0; i <= index; i++) + { + uint8_t current_id = data[ind++]; + uint8_t current_length = data[ind++]; + + if(obj_id) + *obj_id = current_id; + if(obj_length) + *obj_length = current_length; + + if(i == index) + { + for(int j = 0; j < current_length; j++) + { + obj_data[j] = data[ind++]; + } + obj_data[current_length] = '\0'; // добавляем \0 + return 1; + } + else + { + // Пропускаем данные этого объекта + ind += current_length; + } + } + + return 0; +} + + + /** - * @brief Write Object of Device Identification to MessageData - * @param mbdata Указатель на массив данных в структуре RS_MsgTypeDef. - * @return obj Объект для записи. - */ + * @brief Записать Один Объект Идентификатора в массив данных + * @param mbdata Указатель на массив данных в структуре RS_MsgTypeDef. + * @return obj Объект для записи. + */ void MB_WriteSingleObjectToMessage(char *mbdata, unsigned *ind, MB_DeviceObjectTypeDef *obj) { mbdata[(*ind)++] = obj->length; @@ -34,10 +143,10 @@ void MB_WriteSingleObjectToMessage(char *mbdata, unsigned *ind, MB_DeviceObjectT /** - * @brief Write Object of Device Identification to MessageData - * @param mbdata Указатель на массив данных в структуре RS_MsgTypeDef. - * @return obj Объект для записи. - */ + * @brief Записать Массив Объектов Идентификатора в массив данных + * @param mbdata Указатель на массив данных в структуре RS_MsgTypeDef. + * @return obj Объект для записи. + */ void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj) { MB_DeviceObjectTypeDef *obj = (MB_DeviceObjectTypeDef *)&MB_DEVID; @@ -85,16 +194,16 @@ void MB_WriteObjectsToMessage(RS_MsgTypeDef *modbus_msg, unsigned maxidofobj) /** - * @brief Proccess command Read Device Identification (43/14 - 0x2B/0E). + * @brief Обработать функцию Read Device Identifications (43/14 - 0x2B/0E). * @param modbus_msg Указатель на структуру собщения modbus. * @return fMessageHandled Статус о результате обработки комманды. * @details Обработка команды Write Single Register. */ -uint8_t MB_Proccess_Read_Device_Identification(RS_MsgTypeDef *modbus_msg) +uint8_t MB_Process_Read_Device_Identifications(RS_MsgTypeDef *modbus_msg) { switch(modbus_msg->DevId.ReadDevId) { - case MB_BASIC_IDENTIFICATION: + case MB_BASIC_IDENTIFICATIONS: if (modbus_msg->DevId.NextObjId == 0) { modbus_msg->DevId.NextObjId = 0; @@ -104,7 +213,7 @@ uint8_t MB_Proccess_Read_Device_Identification(RS_MsgTypeDef *modbus_msg) modbus_msg->DevId.NumbOfObj = 3; break; - case MB_REGULAR_IDENTIFICATION: + case MB_REGULAR_IDENTIFICATIONS: if (modbus_msg->DevId.NextObjId == 0) { modbus_msg->DevId.NextObjId = 3; @@ -114,7 +223,12 @@ uint8_t MB_Proccess_Read_Device_Identification(RS_MsgTypeDef *modbus_msg) modbus_msg->DevId.NumbOfObj = 4; break; - case MB_EXTENDED_IDENTIFICATION: + case MB_EXTENDED_IDENTIFICATIONS: + if(MODBUS_NUMB_OF_USEROBJECTS <= 0 || MODBUS_NUMB_OF_USEROBJECTS > 128) + { + return 0; + } + if (modbus_msg->DevId.NextObjId == 0) { modbus_msg->DevId.NextObjId = 0x80; @@ -124,7 +238,7 @@ uint8_t MB_Proccess_Read_Device_Identification(RS_MsgTypeDef *modbus_msg) modbus_msg->DevId.NumbOfObj = MODBUS_NUMB_OF_USEROBJECTS; break; - case MB_SPEDIFIC_IDENTIFICATION: + case MB_SPEDIFIC_IDENTIFICATIONS: MB_WriteObjectsToMessage(modbus_msg, modbus_msg->DevId.NextObjId); modbus_msg->DevId.NumbOfObj = 1; break; @@ -136,8 +250,9 @@ uint8_t MB_Proccess_Read_Device_Identification(RS_MsgTypeDef *modbus_msg) - - +/** + * @brief Инициализация идентификаторов. + */ void MB_DeviceInentificationInit(void) { MB_ObjectInit(&MB_DEVID.VendorName, MODBUS_VENDOR_NAME); @@ -533,3 +648,16 @@ void MB_DeviceInentificationInit(void) #endif } + +#else //MODBUS_ENABLE_DEVICE_IDENTIFICATIONS + +/* Получить количество объектов в сообщении */ +int MB_GetNumberOfObjects(RS_MsgTypeDef *modbus_msg) {return 0;} +int MB_FindObjectById(RS_MsgTypeDef *modbus_msg, uint8_t obj_id, char *obj_data, uint8_t *obj_length) {return 0;} +int MB_GetObjectByIndex(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 \ No newline at end of file diff --git a/Modbus/Src/modbus_diag.c b/Modbus/Src/modbus_diag.c new file mode 100644 index 0000000..b0d656d --- /dev/null +++ b/Modbus/Src/modbus_diag.c @@ -0,0 +1,328 @@ +/** +****************************************************************************** +* @file modbus_diag.c +* @brief Реализация диагностики устройства Modbus +****************************************************************************** +* @details +Модуль обработки запросов диагностической информации (0x08): +- Полная поддержка всех подфункций диагностики согласно спецификации Modbus +- Выставление любого бита в Diagnostics Register +- Сбор статистики работы устройства +- Управление режимами работы (Normal/Listen Only) +******************************************************************************/ +#include "modbus_diag.h" + +#ifdef MODBUS_ENABLE_DIAGNOSTICS + +MB_DiagnosticsInfoTypeDef MB_DIAG = {0}; ///< Глобальная структура диагностики + +/** + * @brief Инициализация диагностических счетчиков + */ +void MB_DiagnosticsInit(void) +{ + MB_DIAG.DiagnosticRegister = 0; + MB_DIAG.DeviceMode = MODBUS_NORMAL_MODE; + + // Инициализация счетчиков + MB_DIAG.Counters.BusMessage = 0; + MB_DIAG.Counters.BusCommunicationErr = 0; + MB_DIAG.Counters.BusExceptionErr = 0; + MB_DIAG.Counters.SlaveMessage = 0; + MB_DIAG.Counters.SlaveNoResponse = 0; + MB_DIAG.Counters.SlaveNAK = 0; + MB_DIAG.Counters.SlaveBusy = 0; + MB_DIAG.Counters.BusCharacterOverrun = 0; +} + + +/** + * @brief Получить данные диагностики из сообщения (DATA[1]) + * @param modbus_msg Указатель на структуру сообщения + * @param data Указатель куда положить данные + * @return 1 - успех, 0 - ошибка + */ +int MB_GetDiagnosticResponse(RS_MsgTypeDef *modbus_msg, uint16_t *data) +{ + if(modbus_msg == NULL || data == NULL) + return 0; + + *data = modbus_msg->DATA[1]; + return 1; +} + +/** + * @brief Выставить бит в регистре диагностике + * @param bit_num Номер бита для выставления (1-15, 0 бит нельзя выставить) + * @param bit_state Состояние бита для выставления (Выставить/Сбросить) + * @return >0 - номер выставленного бита, 0 - ошибка + */ +int MB_Diagnostics_WriteBit(int bit_num, int bit_state) +{ + if(bit_num == 0 || bit_num > 15) + return 0; + + if(bit_state) + MB_DIAG.DiagnosticRegister |= (1 << bit_num); + else + MB_DIAG.DiagnosticRegister &= ~(1 << bit_num); + + return bit_num; +} +/** + * @brief Прочитать состояние бита диагностического регистра + * @param bit_num Номер бита (0-15) + * @return 1 - бит установлен, 0 - бит сброшен или ошибка + */ +int MB_Diagnostics_GetBit(int bit_num) +{ + if(bit_num < 0 || bit_num > 15) + return 0; + + return (MB_DIAG.DiagnosticRegister >> bit_num) & 0x01; +} + +/** + * @brief Обработать функцию Diagnostics (Serial Line only) (0x08) + * @param modbus_msg Указатель на структуру сообщения modbus + * @return fMessageHandled Статус обработки команды + */ +uint8_t MB_Process_Diagnostics(RS_MsgTypeDef *modbus_msg) +{ + uint16_t sub_function = modbus_msg->DATA[0]; + uint16_t request_data = modbus_msg->DATA[1]; + + // Если устройство в режиме Listen Only, отвечаем только на sub-function 0x01 + if (MB_DIAG.DeviceMode == MODBUS_LISTEN_ONLY_MODE && sub_function != 0x0001) + { + return 0; // Не отвечаем в режиме Listen Only + } + + switch(sub_function) + { + case 0x0000: // Return Query Data + // Эхо-ответ с теми же данными + modbus_msg->DATA[0] = sub_function; + modbus_msg->DATA[1] = request_data; + modbus_msg->ByteCnt = 4; + break; + + case 0x0001: // Restart Communications + // Перезапуск коммуникаций - выходим из Listen Only режима + MB_DIAG.DeviceMode = MODBUS_NORMAL_MODE; + + // Если request_data = 0xFF00, очищаем лог событий + if (request_data == 0xFF00) + { + MB_DiagnosticsInit(); // Полный сброс + } + else + { + // Очищаем только счетчики, но не регистр диагностики + MB_DIAG.Counters.BusMessage = 0; + MB_DIAG.Counters.BusCommunicationErr = 0; + MB_DIAG.Counters.BusExceptionErr = 0; + MB_DIAG.Counters.SlaveMessage = 0; + MB_DIAG.Counters.SlaveNoResponse = 0; + MB_DIAG.Counters.SlaveNAK = 0; + MB_DIAG.Counters.SlaveBusy = 0; + MB_DIAG.Counters.BusCharacterOverrun = 0; + } + + modbus_msg->DATA[0] = sub_function; + modbus_msg->DATA[1] = request_data; + modbus_msg->ByteCnt = 4; + break; + + case 0x0002: // Return Diagnostic Register + modbus_msg->DATA[0] = sub_function; + modbus_msg->DATA[1] = MB_DIAG.DiagnosticRegister; + modbus_msg->ByteCnt = 4; + break; + + case 0x0003: // Change ASCII Input Delimiter + // В RTU режиме не поддерживается + modbus_msg->Func_Code |= ERR_VALUES_START; + modbus_msg->Except_Code = ILLEGAL_FUNCTION; + return 0; + + case 0x0004: // Force Listen Only Mode + MB_DIAG.DeviceMode = MODBUS_LISTEN_ONLY_MODE; + // В режиме Listen Only не отправляем ответ + return 0; + + case 0x000A: // Clear Counters and Diagnostic Register + MB_DiagnosticsInit(); // Полный сброс + modbus_msg->DATA[0] = sub_function; + modbus_msg->DATA[1] = 0; + modbus_msg->ByteCnt = 4; + break; + + case 0x000B: // Return Bus Message Count + modbus_msg->DATA[0] = sub_function; + modbus_msg->DATA[1] = MB_DIAG.Counters.BusMessage; + modbus_msg->ByteCnt = 4; + break; + + case 0x000C: // Return Bus Communication Error Count + modbus_msg->DATA[0] = sub_function; + modbus_msg->DATA[1] = MB_DIAG.Counters.BusCommunicationErr; + modbus_msg->ByteCnt = 4; + break; + + case 0x000D: // Return Bus Exception Error Count + modbus_msg->DATA[0] = sub_function; + modbus_msg->DATA[1] = MB_DIAG.Counters.BusExceptionErr; + modbus_msg->ByteCnt = 4; + break; + + case 0x000E: // Return Server Message Count + modbus_msg->DATA[0] = sub_function; + modbus_msg->DATA[1] = MB_DIAG.Counters.SlaveMessage; + modbus_msg->ByteCnt = 4; + break; + + case 0x000F: // Return Slave No Response Count + modbus_msg->DATA[0] = sub_function; + modbus_msg->DATA[1] = MB_DIAG.Counters.SlaveNoResponse; + modbus_msg->ByteCnt = 4; + break; + + case 0x0010: // Return Slave NAK Count + modbus_msg->DATA[0] = sub_function; + modbus_msg->DATA[1] = MB_DIAG.Counters.SlaveNAK; + modbus_msg->ByteCnt = 4; + break; + + case 0x0011: // Return Slave Busy Count + modbus_msg->DATA[0] = sub_function; + modbus_msg->DATA[1] = MB_DIAG.Counters.SlaveBusy; + modbus_msg->ByteCnt = 4; + break; + + case 0x0012: // Return Bus Character Overrun Count + modbus_msg->DATA[0] = sub_function; + modbus_msg->DATA[1] = MB_DIAG.Counters.BusCharacterOverrun; + modbus_msg->ByteCnt = 4; + break; + + case 0x0014: // Clear Overrun Counter and Flag + MB_DIAG.Counters.BusCharacterOverrun = 0; + // Сбрасываем флаг переполнения в DiagnosticRegister + MB_DIAG.DiagnosticRegister &= ~(1<<0); + modbus_msg->DATA[0] = sub_function; + modbus_msg->DATA[1] = 0; + modbus_msg->ByteCnt = 4; + break; + + default: + modbus_msg->Func_Code |= ERR_VALUES_START; + modbus_msg->Except_Code = ILLEGAL_FUNCTION; + return 0; + } + + return 1; +} + +/** + * @brief Увеличивает счетчик сообщений на шине + */ +void MB_Diagnostics_BusMessageCnt(void) +{ + MB_DIAG.Counters.BusMessage++; +} + +/** + * @brief Увеличивает счетчик ошибок связи + */ +void MB_Diagnostics_CommunicationErrorCnt(void) +{ + if (MB_DIAG.Counters.BusCommunicationErr < 0xFFFF) + MB_DIAG.Counters.BusCommunicationErr++; +} + +/** + * @brief Увеличивает счетчик исключений + */ +void MB_Diagnostics_ExceptionErrorCnt(void) +{ + if (MB_DIAG.Counters.BusExceptionErr < 0xFFFF) + MB_DIAG.Counters.BusExceptionErr++; +} + +/** + * @brief Увеличивает счетчик переполнения символов + */ +void MB_Diagnostics_CharacterOverrunCnt(void) +{ + if (MB_DIAG.Counters.BusCharacterOverrun < 0xFFFF) + { + MB_DIAG.Counters.BusCharacterOverrun++; + // Устанавливаем флаг переполнения в DiagnosticRegister + MB_DIAG.DiagnosticRegister |= (1 << 0); + } +} + +/** + * @brief Увеличивает счетчик отсутствия ответов + */ +void MB_Diagnostics_SlaveMessageCnt(void) +{ + if (MB_DIAG.Counters.SlaveMessage < 0xFFFF) + MB_DIAG.Counters.SlaveMessage++; +} + +/** + * @brief Увеличивает счетчик отсутствия ответов + */ +void MB_Diagnostics_SlaveNoResponseCnt(void) +{ + if (MB_DIAG.Counters.SlaveNoResponse < 0xFFFF) + MB_DIAG.Counters.SlaveNoResponse++; +} + +/** + * @brief Увеличивает счетчик NAK ответов + */ +void MB_Diagnostics_SlaveNAKCnt(void) +{ + if (MB_DIAG.Counters.SlaveNAK < 0xFFFF) + MB_DIAG.Counters.SlaveNAK++; +} + +/** + * @brief Увеличивает счетчик занятости устройства + */ +void MB_Diagnostics_SlaveBusyCnt(void) +{ + if (MB_DIAG.Counters.SlaveBusy < 0xFFFF) + MB_DIAG.Counters.SlaveBusy++; +} + +/** + * @brief Получение текущего режима устройства + * @return Текущий режим работы устройства + */ +MB_DeviceModeTypeDef MB_GetDeviceMode(void) +{ + return MB_DIAG.DeviceMode; +} + +#else //MODBUS_ENABLE_DIAGNOSTICS + +void MB_DiagnosticsInit(void) {} +int MB_GetDiagnosticResponse(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 \ No newline at end of file diff --git a/Modbus/Src/modbus_holdregs.c b/Modbus/Src/modbus_holdregs.c index 2f293d3..64760b7 100644 --- a/Modbus/Src/modbus_holdregs.c +++ b/Modbus/Src/modbus_holdregs.c @@ -21,13 +21,16 @@ #include "modbus_inputregs.h" +#ifdef MODBUS_ENABLE_HOLDINGS + + /** - * @brief Proccess command Read Holding Registers (03 - 0x03). + * @brief Обработать функцию Read Holding Registers (03 - 0x03). * @param modbus_msg Указатель на структуру собщения modbus. * @return fMessageHandled Статус о результате обработки комманды. * @details Обработка команды Read Holding Registers. */ -uint8_t MB_Proccess_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg) +uint8_t MB_Process_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg) { //---------CHECK FOR ERRORS---------- // get origin address for data @@ -50,12 +53,12 @@ uint8_t MB_Proccess_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg) } /** - * @brief Proccess command Write Single Register (06 - 0x06). + * @brief Обработать функцию Write Single Register (06 - 0x06). * @param modbus_msg Указатель на структуру собщения modbus. * @return fMessageHandled Статус о результате обработки комманды. * @details Обработка команды Write Single Register. */ -uint8_t MB_Proccess_Write_Single_Reg(RS_MsgTypeDef *modbus_msg) +uint8_t MB_Process_Write_Single_Reg(RS_MsgTypeDef *modbus_msg) { // get origin address for data uint16_t *pHoldRegs; @@ -69,12 +72,12 @@ uint8_t MB_Proccess_Write_Single_Reg(RS_MsgTypeDef *modbus_msg) } /** - * @brief Proccess command Write Multiple Registers (16 - 0x10). + * @brief Обработать функцию Write Multiple Registers (16 - 0x10). * @param modbus_msg Указатель на структуру собщения modbus. * @return fMessageHandled Статус о результате обработки комманды. * @details Обработка команды Write Multiple Registers. */ -uint8_t MB_Proccess_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg) +uint8_t MB_Process_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg) { //---------CHECK FOR ERRORS---------- if (modbus_msg->Qnt*2 != modbus_msg->ByteCnt) @@ -95,3 +98,12 @@ uint8_t MB_Proccess_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg) } return 1; } + + +#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 \ No newline at end of file diff --git a/Modbus/Src/modbus_inputregs.c b/Modbus/Src/modbus_inputregs.c index cf300df..3bc34c9 100644 --- a/Modbus/Src/modbus_inputregs.c +++ b/Modbus/Src/modbus_inputregs.c @@ -9,17 +9,18 @@ Копирование данных из структур устройства в буфер ответа - Поддержка знаковых и беззнаковых значений ******************************************************************************/ - #include "modbus_inputregs.h" +#ifdef MODBUS_ENABLE_INPUTS + /** - * @brief Proccess command Read Input Registers (04 - 0x04). + * @brief Обработать функцию Read Input Registers (04 - 0x04). * @param modbus_msg Указатель на структуру собщения modbus. * @return fMessageHandled Статус о результате обработки комманды. * @details Обработка команды Read Input Registers. */ -uint8_t MB_Proccess_Read_Input_Regs(RS_MsgTypeDef *modbus_msg) +uint8_t MB_Process_Read_Input_Regs(RS_MsgTypeDef *modbus_msg) { //---------CHECK FOR ERRORS---------- // get origin address for data @@ -43,3 +44,9 @@ uint8_t MB_Proccess_Read_Input_Regs(RS_MsgTypeDef *modbus_msg) } return 1; } + +#else //MODBUS_ENABLE_INPUTS + +uint8_t MB_Process_Read_Input_Regs(RS_MsgTypeDef *modbus_msg) {return 0;} + +#endif \ No newline at end of file diff --git a/Modbus/Src/modbus_master.c b/Modbus/Src/modbus_master.c new file mode 100644 index 0000000..90cb7dd --- /dev/null +++ b/Modbus/Src/modbus_master.c @@ -0,0 +1,519 @@ +/** +************************************************************************** +* @file modbus_master.c +* @brief Модуль для реализации мастера MODBUS. +************************************************************************** +* @details +Файл содержит реализацию функций для работы Modbus в режиме мастера. + +@section Функции и макросы + +- MB_Master_Collect_Message() — Сбор сообщения в режиме мастера +- MB_Master_Parse_Message() — Парс сообщения в режиме мастера +******************************************************************************/ +#include "modbus.h" + +#ifdef MODBUS_ENABLE_MASTER + + +/** + * @brief Получить значение регистра из ответа по его адресу + * @param modbus_msg Указатель на структуру сообщения + * @param reg_addr Адрес регистра, значение которого нужно получить + * @param reg_value Указатель для значения регистра + * @return 1 - успех, 0 - ошибка или reg_addr вне диапазона запроса + */ +int MB_GetRegisterValue(RS_MsgTypeDef *modbus_msg, uint16_t reg_addr, uint16_t *reg_value) +{ + if(modbus_msg == NULL || reg_value == NULL) + return 0; + + // Проверяем что reg_addr в пределах запрошенного диапазона + if(reg_addr < modbus_msg->Addr || reg_addr >= modbus_msg->Addr + modbus_msg->Qnt) + return 0; + + // Вычисляем индекс регистра в полученных данных + uint16_t reg_index = reg_addr - modbus_msg->Addr; + + // Проверяем что регистр существует в данных + if(reg_index >= modbus_msg->ByteCnt / 2) + return 0; + + // Получаем значение регистра + *reg_value = modbus_msg->DATA[reg_index]; + + return 1; +} + +/** + * @brief Определить размер модбас запроса (МАСТЕР версия). + * @param hRS Указатель на хендлер RS. + * @param rx_data_size Указатель на переменную для записи кол-ва байт для принятия. + * @return RS_RES Статус о корректности рассчета кол-ва байт для принятия. + * @details Определение сколько байтов надо принять по протоколу. + */ +static int MB_Define_Size_of_Function(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) +{ + RS_StatusTypeDef MB_RES = 0; + int mb_func_size = 0; + + + // Master mode - calculating response size from slave + if (modbus_msg->Func_Code & ERR_VALUES_START) + { + // Error response: [Addr][Func|0x80][ExceptCode][CRC] + mb_func_size = -1; // Only Exception Code + } + else if (modbus_msg->Func_Code == MB_R_DIAGNOSTIC) + { + // Diagnostics response: [SubFunc_HI][SubFunc_LO][Data_HI][Data_LO] + mb_func_size = 1; + } + else if (modbus_msg->Func_Code == MB_R_DEVICE_INFO) + { + // Device identifications: variable size, need to read first to determine + mb_func_size = 0; // Will be determined after reading header + } + else + { + switch (modbus_msg->Func_Code & ~ERR_VALUES_START) + { + case 0x01: // Read Coils + case 0x02: // Read Discrete Inputs + case 0x03: // Read Holding Registers + case 0x04: // Read Input Registers + // Response: [ByteCount][Data...] + mb_func_size = modbus_msg->ByteCnt + 2; // ByteCount + variable data + break; + + case 0x05: // Write Single Coil + case 0x06: // Write Single Register + // Echo response: [Addr][Value][CRC] + mb_func_size = 4; // Address(2) + Value(2) + break; + + case 0x0F: // Write Multiple Coils + case 0x10: // Write Multiple Registers + // Echo response: [Addr][Qty][CRC] + mb_func_size = 4; // Address(2) + Quantity(2) + break; + + default: + mb_func_size = 0; + } + } + + mb_func_size = RX_FIRST_PART_SIZE + mb_func_size; // size of whole message + return mb_func_size; +} + +/** + * @brief Сбор сообщения в буфер UART в режиме мастер (фрейм мастера из msg -> uart). + * @param hmodbus Указатель на хендлер RS. + * @param modbus_msg Указатель на структуру сообщения. + * @param modbus_uart_buff Указатель на буффер UART. + * @return RS_RES Статус о результате заполнения буфера. + */ +RS_StatusTypeDef MB_Master_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff) +{ + int ind = 0; // ind for modbus-uart buffer + + //------INFO ABOUT DATA/MESSAGE------ + //-----------[first bytes]----------- + // set ID of slave device + modbus_uart_buff[ind++] = modbus_msg->MbAddr; + + // set function code + modbus_uart_buff[ind++] = modbus_msg->Func_Code; + + if(modbus_msg->Func_Code < ERR_VALUES_START) // if no error occur + { + // fill modbus header + if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) // device identifications request + { + modbus_uart_buff[ind++] = modbus_msg->DevId.MEI_Type; + modbus_uart_buff[ind++] = modbus_msg->DevId.ReadDevId; + modbus_uart_buff[ind++] = modbus_msg->DevId.NextObjId; + } + else if(modbus_msg->Func_Code == MB_R_DIAGNOSTIC) + { + // Diagnostics: [SubFunc_HI][SubFunc_LO][Data_HI][Data_LO] + modbus_uart_buff[ind++] = modbus_msg->DATA[0] >> 8; // Sub-function HI + modbus_uart_buff[ind++] = modbus_msg->DATA[0] & 0xFF; // Sub-function LO + modbus_uart_buff[ind++] = modbus_msg->DATA[1] >> 8; // Data HI + modbus_uart_buff[ind++] = modbus_msg->DATA[1] & 0xFF; // Data LO + } + else // classic modbus request + { + // set address + modbus_uart_buff[ind++] = modbus_msg->Addr >> 8; + modbus_uart_buff[ind++] = modbus_msg->Addr & 0xFF; + + // set quantity + modbus_uart_buff[ind++] = modbus_msg->Qnt >> 8; + modbus_uart_buff[ind++] = modbus_msg->Qnt & 0xFF; + + // for write multiple functions + if((modbus_msg->Func_Code == 0x0F) || (modbus_msg->Func_Code == 0x10)) + { + modbus_uart_buff[ind++] = modbus_msg->ByteCnt; + + // write data bytes + uint8_t *tmp_data_addr = (uint8_t *)modbus_msg->DATA; + for(int i = 0; i < modbus_msg->ByteCnt; i++) + { + modbus_uart_buff[ind++] = tmp_data_addr[i]; + } + } + } + } + + if(ind < 0) + return RS_COLLECT_MSG_ERR; + + //---------------CRC---------------- + //---------[last 2 bytes]---------- + uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind); + modbus_msg->MB_CRC = CRC_VALUE; + modbus_uart_buff[ind++] = CRC_VALUE & 0xFF; + modbus_uart_buff[ind++] = CRC_VALUE >> 8; + + hmodbus->RS_Message_Size = ind; + + return RS_OK; +} + +/** + * @brief Парс сообщения в режиме мастер (фрейм слейва из uart -> msg). + * @param hmodbus Указатель на хендлер RS. + * @param modbus_msg Указатель на структуру сообщения. + * @param modbus_uart_buff Указатель на буффер UART. + * @return RS_RES Статус о результате заполнения структуры. + */ +RS_StatusTypeDef MB_Master_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff) +{ + int ind = 0; // ind for modbus-uart buffer + int expected_size = 0; + + // get ID of slave device + modbus_msg->MbAddr = modbus_uart_buff[ind++]; + + // get function code (check if error response) + modbus_msg->Func_Code = modbus_uart_buff[ind++]; + + if(modbus_msg->Func_Code & ERR_VALUES_START) // error response + { + modbus_msg->Except_Code = modbus_uart_buff[ind++]; + } + else if(modbus_msg->Func_Code < ERR_VALUES_START) // normal response + { + if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) // device identifications response + { + modbus_msg->DevId.MEI_Type = modbus_uart_buff[ind++]; + modbus_msg->DevId.ReadDevId = modbus_uart_buff[ind++]; + modbus_msg->DevId.Conformity = modbus_uart_buff[ind++]; + modbus_msg->DevId.MoreFollows = modbus_uart_buff[ind++]; + modbus_msg->DevId.NextObjId = modbus_uart_buff[ind++]; + modbus_msg->DevId.NumbOfObj = modbus_uart_buff[ind++]; + + modbus_msg->ByteCnt = 0; + + // Парсинг объектов идентификации устройства + uint8_t *tmp_data_addr = (uint8_t *)modbus_msg->DATA; + int data_index = 0; + + for(int obj = 0; obj < modbus_msg->DevId.NumbOfObj; obj++) + { + // Читаем ID объекта + uint8_t object_id = modbus_uart_buff[ind++]; + tmp_data_addr[data_index++] = object_id; + + // Читаем длину объекта + uint8_t object_length = modbus_uart_buff[ind++]; + tmp_data_addr[data_index++] = object_length; + + // Читаем данные объекта + for(int i = 0; i < object_length; i++) + { + tmp_data_addr[data_index++] = modbus_uart_buff[ind++]; + } + + modbus_msg->ByteCnt += (2 + object_length); // ID + длина + данные + } + } + else if(modbus_msg->Func_Code == MB_R_DIAGNOSTIC) + { + // Diagnostics response: [SubFunc_HI][SubFunc_LO][Data_HI][Data_LO] + modbus_msg->DATA[0] = modbus_uart_buff[ind++] << 8; + modbus_msg->DATA[0] |= modbus_uart_buff[ind++]; + modbus_msg->DATA[1] = modbus_uart_buff[ind++] << 8; + modbus_msg->DATA[1] |= modbus_uart_buff[ind++]; + } + else // classic modbus response + { + // get byte count for read functions + if((modbus_msg->Func_Code == 0x01) || (modbus_msg->Func_Code == 0x02) || + (modbus_msg->Func_Code == 0x03) || (modbus_msg->Func_Code == 0x04)) + { + modbus_msg->ByteCnt = modbus_uart_buff[ind++]; + + // read data bytes + uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->DATA; + for(int i = 0; i < modbus_msg->ByteCnt; i++) + { + if(i % 2 == 0) // HI byte + tmp_data_addr[i/2] = (uint16_t)modbus_uart_buff[ind++] << 8; + else // LO byte + tmp_data_addr[i/2] |= modbus_uart_buff[ind++]; + } + } + // for write functions - echo address and quantity + else if((modbus_msg->Func_Code == 0x05) || (modbus_msg->Func_Code == 0x06) || + (modbus_msg->Func_Code == 0x0F) || (modbus_msg->Func_Code == 0x10)) + { + modbus_msg->Addr = modbus_uart_buff[ind++] << 8; + modbus_msg->Addr |= modbus_uart_buff[ind++]; + modbus_msg->Qnt = modbus_uart_buff[ind++] << 8; + modbus_msg->Qnt |= modbus_uart_buff[ind++]; + } + } + } + + + //---------------CRC---------------- + //----------[last 2 bytes]---------- + uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind); + modbus_msg->MB_CRC = modbus_uart_buff[ind++]; + modbus_msg->MB_CRC |= modbus_uart_buff[ind++] << 8; + + if(modbus_msg->MB_CRC != CRC_VALUE) + { + TrackerCnt_Err(hmodbus->rs_err); + return RS_PARSE_MSG_ERR; + } + + return RS_OK; +} + + + + + +/** @brief Сформировать запрос на чтение коилов */ +RS_MsgTypeDef MB_REQUEST_READ_COILS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity) +{ + RS_MsgTypeDef msg = {slave_addr, MB_R_COILS, {0}, start_addr, quantity, 0, {0}, 0, 0}; + return msg; +} + +/** @brief Сформировать запрос на чтение дискретных регистров */ +RS_MsgTypeDef MB_REQUEST_READ_DISCRETE_INPUTS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity) +{ + RS_MsgTypeDef msg = {slave_addr, MB_R_DISC_IN, {0}, start_addr, quantity, 0, {0}, 0, 0}; + return msg; +} + +/** @brief Сформировать запрос на чтение холдинг регистров */ +RS_MsgTypeDef MB_REQUEST_READ_HOLDING_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity) +{ + RS_MsgTypeDef msg = {slave_addr, MB_R_HOLD_REGS, {0}, start_addr, quantity, 0, {0}, 0, 0}; + return msg; +} + +/** @brief Сформировать запрос на чтение инпут регистров */ +RS_MsgTypeDef MB_REQUEST_READ_INPUT_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity) +{ + RS_MsgTypeDef msg = {slave_addr, MB_R_IN_REGS, {0}, start_addr, quantity, 0, {0}, 0, 0}; + return msg; +} + +/** @brief Сформировать запрос на запись одного коила */ +RS_MsgTypeDef MB_REQUEST_WRITE_SINGLE_COIL(uint8_t slave_addr, uint16_t coil_addr, uint8_t value) +{ + RS_MsgTypeDef msg = {slave_addr, MB_W_COIL, {0}, coil_addr, (value ? 0xFF00 : 0x0000), 0, {0}, 0, 0}; + return msg; +} + +/** @brief Сформировать запрос на запись одного регистра */ +RS_MsgTypeDef MB_REQUEST_WRITE_SINGLE_REG(uint8_t slave_addr, uint16_t reg_addr, uint16_t value) +{ + RS_MsgTypeDef msg = {slave_addr, MB_W_HOLD_REG, {0}, reg_addr, value, 0, {0}, 0, 0}; + return msg; +} + +/** @brief Сформировать запрос на запись нескольких регистров */ +RS_MsgTypeDef MB_REQUEST_WRITE_MULTIPLE_COILS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity, uint8_t *coils_data) +{ + RS_MsgTypeDef msg = {slave_addr, MB_W_COILS, {0}, start_addr, quantity, 0, {0}, 0, 0}; + + // Calculate byte count and prepare data + uint8_t byte_count = (quantity + 7) / 8; + msg.ByteCnt = byte_count; + + // Copy coil data to message DATA array + for(int i = 0; i < byte_count; i++) { + if(i < DATA_SIZE) { + msg.DATA[i] = coils_data[i]; + } + } + + return msg; +} + +/** @brief Сформировать запрос на запись нескольких коилов */ +RS_MsgTypeDef MB_REQUEST_WRITE_MULTIPLE_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity, uint16_t *regs_data) +{ + RS_MsgTypeDef msg = {slave_addr, MB_W_HOLD_REGS, {0}, start_addr, quantity, 0, {0}, 0, 0}; + + msg.ByteCnt = quantity * 2; // Each register is 2 bytes + + // Copy register data to message DATA array + for(int i = 0; i < quantity && i < DATA_SIZE; i++) { + msg.DATA[i] = regs_data[i]; + } + + return msg; +} + +//---------ДИАГНОСТИЧЕСКИЕ ДАННЫЕ----------- +RS_MsgTypeDef MB_REQUEST_DIAGNOSTIC_QUERY(uint8_t slave_addr, uint16_t sub_function, uint16_t data) +{ + RS_MsgTypeDef msg = {slave_addr, MB_R_DIAGNOSTIC, {0}, 0, 0, 0, {sub_function, data}, 0, 0}; + return msg; +} +RS_MsgTypeDef MB_REQUEST_RETURN_QUERY_DATA(uint8_t slave_addr) +{ + return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0000, 0x0000); +} + +RS_MsgTypeDef MB_REQUEST_RESTART_COMMUNICATIONS(uint8_t slave_addr, uint16_t data) +{ + return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0001, data); +} + +RS_MsgTypeDef MB_REQUEST_RETURN_DIAGNOSTIC_REGISTER(uint8_t slave_addr) +{ + return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0002, 0x0000); +} + +RS_MsgTypeDef MB_REQUEST_FORCE_LISTEN_ONLY_MODE(uint8_t slave_addr) +{ + return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0004, 0x0000); +} + +RS_MsgTypeDef MB_REQUEST_CLEAR_COUNTERS_AND_DIAGNOSTIC_REGISTER(uint8_t slave_addr) +{ + return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x000A, 0x0000); +} + +RS_MsgTypeDef MB_REQUEST_RETURN_BUS_MESSAGE_COUNT(uint8_t slave_addr) +{ + return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x000B, 0x0000); +} + +RS_MsgTypeDef MB_REQUEST_RETURN_BUS_COMMUNICATION_ERROR_COUNT(uint8_t slave_addr) +{ + return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x000C, 0x0000); +} + +RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_EXCEPTION_ERROR_COUNT(uint8_t slave_addr) +{ + return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x000D, 0x0000); +} + +RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_MESSAGE_COUNT(uint8_t slave_addr) +{ + return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x000E, 0x0000); +} + +RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_NO_RESPONSE_COUNT(uint8_t slave_addr) +{ + return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x000F, 0x0000); +} + +RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_NAK_COUNT(uint8_t slave_addr) +{ + return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0010, 0x0000); +} + +RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_BUSY_COUNT(uint8_t slave_addr) +{ + return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0011, 0x0000); +} + +RS_MsgTypeDef MB_REQUEST_RETURN_BUS_CHARACTER_OVERRUN_COUNT(uint8_t slave_addr) +{ + return MB_REQUEST_DIAGNOSTIC_QUERY(slave_addr, 0x0012, 0x0000); +} + +//---------ИДЕНТИФИКАТОРЫ МОДБАС----------- +RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_BASIC(uint8_t slave_addr) +{ + RS_MsgTypeDef msg = {slave_addr, MB_R_DEVICE_INFO, {0x0E, 0x01, 0x00, 0, 0, 0}, 0, 0, 0, {0}, 0, 0}; + return msg; +} + +RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_REGULAR(uint8_t slave_addr) +{ + RS_MsgTypeDef msg = {slave_addr, MB_R_DEVICE_INFO, {0x0E, 0x02, 0x00, 0, 0, 0}, 0, 0, 0, {0}, 0, 0}; + return msg; +} + +RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_EXTENDED(uint8_t slave_addr) +{ + RS_MsgTypeDef msg = {slave_addr, MB_R_DEVICE_INFO, {0x0E, 0x03, 0x00, 0, 0, 0}, 0, 0, 0, {0}, 0, 0}; + return msg; +} + +RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_SPECIFIC(uint8_t slave_addr, uint8_t object_id) +{ + RS_MsgTypeDef msg = {slave_addr, MB_R_DEVICE_INFO, {0x0E, 0x04, object_id, 0, 0, 0}, 0, 0, 0, {0}, 0, 0}; + return msg; +} + + + + + +#else +RS_MsgTypeDef msg_dummy = {0}; + +int MB_GetRegisterValue(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 + + + diff --git a/Modbus/Src/modbus_slave.c b/Modbus/Src/modbus_slave.c new file mode 100644 index 0000000..80311ba --- /dev/null +++ b/Modbus/Src/modbus_slave.c @@ -0,0 +1,437 @@ +/** +************************************************************************** +* @file modbus_slave.c +* @brief Модуль для реализации слейв MODBUS. +************************************************************************** +* @details +Файл содержит реализацию функций для работы Modbus в режиме слейва. + +@section Функции и макросы + +- MB_Slave_Response() — Ответ на запрос +- MB_Slave_Collect_Message() — Сбор сообщения в режиме слейва. +- MB_Slave_Parse_Message() — Парс сообщения в режиме слейва. +******************************************************************************/ +#include "modbus.h" + +#ifdef MODBUS_ENABLE_SLAVE +/** + * @brief Ответ на сообщение в режиме слейва. + * @param hmodbus Указатель на хендлер RS. + * @param modbus_msg Указатель на структуру сообщения. + * @return RS_RES Статус о результате ответа на комманду. + */ +RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) +{ + RS_StatusTypeDef MB_RES = 0; + hmodbus->f.MessageHandled = 0; + hmodbus->f.EchoResponse = 0; + RS_Reset_TX_Flags(hmodbus); // reset flag for correct transmit + + MB_Diagnostics_BusMessageCnt(); + if(hmodbus->ID == 0 || modbus_msg->MbAddr == 0) + { + MB_Diagnostics_SlaveNoResponseCnt(); // <-- Устройство не отвечает на широковещательные сообщения + hmodbus->RS_STATUS = RS_SKIP; + return RS_Handle_Receive_Start(hmodbus, modbus_msg); + } + MB_Diagnostics_SlaveMessageCnt(); + + if(modbus_msg->Func_Code < ERR_VALUES_START)// if no errors after parsing + { + switch (modbus_msg->Func_Code) + { + // Read Coils + case MB_R_COILS: + hmodbus->f.MessageHandled = MB_Process_Read_Coils(hmodbus->pMessagePtr); + break; + + // Read Hodling Registers + case MB_R_HOLD_REGS: + hmodbus->f.MessageHandled = MB_Process_Read_Hold_Regs(hmodbus->pMessagePtr); + break; + case MB_R_IN_REGS: + hmodbus->f.MessageHandled = MB_Process_Read_Input_Regs(hmodbus->pMessagePtr); + break; + + + // Write Single Coils + case MB_W_COIL: + hmodbus->f.MessageHandled = MB_Process_Write_Single_Coil(hmodbus->pMessagePtr); + if(hmodbus->f.MessageHandled) + { + hmodbus->f.DataUpdated = 1; + hmodbus->f.EchoResponse = 1; + hmodbus->RS_Message_Size -= 2; // echo response if write ok (minus 2 cause of two CRC bytes) + } + break; + + case MB_W_HOLD_REG: + hmodbus->f.MessageHandled = MB_Process_Write_Single_Reg(hmodbus->pMessagePtr); + if(hmodbus->f.MessageHandled) + { + hmodbus->f.DataUpdated = 1; + hmodbus->f.EchoResponse = 1; + hmodbus->RS_Message_Size -= 2; // echo response if write ok (minus 2 cause of two CRC bytes) + } + break; + + // Write Multiple Coils + case MB_W_COILS: + hmodbus->f.MessageHandled = MB_Write_Miltuple_Coils(hmodbus->pMessagePtr); + if(hmodbus->f.MessageHandled) + { + hmodbus->f.DataUpdated = 1; + hmodbus->f.EchoResponse = 1; + hmodbus->RS_Message_Size = 6; // echo response if write ok (withous data bytes) + } + break; + + // Write Multiple Registers + case MB_W_HOLD_REGS: + hmodbus->f.MessageHandled = MB_Process_Write_Miltuple_Regs(hmodbus->pMessagePtr); + if(hmodbus->f.MessageHandled) + { + hmodbus->f.DataUpdated = 1; + hmodbus->f.EchoResponse = 1; + hmodbus->RS_Message_Size = 6; // echo response if write ok (withous data bytes) + } + break; + + case MB_R_DEVICE_INFO: + hmodbus->f.MessageHandled = MB_Process_Read_Device_Identifications(hmodbus->pMessagePtr); + break; + + // Добавить в switch-case после других case: + case MB_R_DIAGNOSTIC: + hmodbus->f.MessageHandled = MB_Process_Diagnostics(hmodbus->pMessagePtr); + break; + + /* unknown func code */ + default: + modbus_msg->Except_Code = 0x01; /* set exception code: illegal function */ + } + + + // Проверяем режим устройства - если Listen Only, не обрабатываем команды + if (MB_GetDeviceMode() == MODBUS_LISTEN_ONLY_MODE) + { + MB_Diagnostics_SlaveNoResponseCnt(); + hmodbus->RS_STATUS = RS_SKIP; + return RS_Handle_Receive_Start(hmodbus, modbus_msg);; + } + + // Проверяем статус обработки запроса + if(hmodbus->f.MessageHandled == 0) + { + MB_Diagnostics_ExceptionErrorCnt(); + TrackerCnt_Warn(hmodbus->rs_err); + modbus_msg->Func_Code |= ERR_VALUES_START; + } + else + { + TrackerCnt_Ok(hmodbus->rs_err); + } + + + } + + // if we need response - check that transmit isnt busy + if( RS_Is_TX_Busy(hmodbus) ) + RS_Abort(hmodbus, ABORT_TX); // if tx busy - set it free + + // Transmit right there, or sets (fDeferredResponse) to transmit response in main code + if(hmodbus->f.DeferredResponse == 0) + { + MB_RES = RS_Handle_Transmit_Start(hmodbus, modbus_msg); + } + else + { + RS_Handle_Receive_Start(hmodbus, modbus_msg); + hmodbus->f.DeferredResponse = 0; + } + + hmodbus->RS_STATUS = MB_RES; + return MB_RES; +} + + + +/** + * @brief Сбор сообщения в буфер UART в режиме слейв (фрейм слейва из msg -> uart). + * @param hmodbus Указатель на хендлер RS. + * @param modbus_msg Указатель на структуру сообщения. + * @param modbus_uart_buff Указатель на буффер UART. + * @return RS_RES Статус о результате заполнения буфера. + */ +RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff) +{ + int ind = 0; // ind for modbus-uart buffer + + if(hmodbus->f.EchoResponse && hmodbus->f.MessageHandled) // if echo response need + ind = hmodbus->RS_Message_Size; + else + { + //------INFO ABOUT DATA/MESSAGE------ + //-----------[first bytes]----------- + // set ID of message/user + modbus_uart_buff[ind++] = modbus_msg->MbAddr; + + // set dat or err response + modbus_uart_buff[ind++] = modbus_msg->Func_Code; + + if (modbus_msg->Func_Code < ERR_VALUES_START) // if no error occur + { + // fill modbus header + if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) // devide identifications header + { + modbus_uart_buff[ind++] = modbus_msg->DevId.MEI_Type; + modbus_uart_buff[ind++] = modbus_msg->DevId.ReadDevId; + modbus_uart_buff[ind++] = modbus_msg->DevId.Conformity; + modbus_uart_buff[ind++] = modbus_msg->DevId.MoreFollows; + modbus_uart_buff[ind++] = modbus_msg->DevId.NextObjId; + modbus_uart_buff[ind++] = modbus_msg->DevId.NumbOfObj; + + if (modbus_msg->ByteCnt > DATA_SIZE*2) // if ByteCnt less than DATA_SIZE + { + TrackerCnt_Err(hmodbus->rs_err); + return RS_COLLECT_MSG_ERR; + } + + + //---------------DATA---------------- + //-----------[data bytes]------------ + uint8_t *tmp_data_addr = (uint8_t *)modbus_msg->DATA; + for(int i = 0; i < modbus_msg->ByteCnt; i++) // filling buffer with data + { // set data + modbus_uart_buff[ind++] = *tmp_data_addr; + tmp_data_addr++; + } + + } + else if(modbus_msg->Func_Code == MB_R_DIAGNOSTIC) + { + // Diagnostics special format: [SubFunc_HI][SubFunc_LO][Data_HI][Data_LO] + modbus_uart_buff[ind++] = modbus_msg->DATA[0] >> 8; // Sub-function HI + modbus_uart_buff[ind++] = modbus_msg->DATA[0] & 0xFF; // Sub-function LO + modbus_uart_buff[ind++] = modbus_msg->DATA[1] >> 8; // Data HI + modbus_uart_buff[ind++] = modbus_msg->DATA[1] & 0xFF; // Data LO + } + else // modbus data header + { + // set size of received data + if (modbus_msg->ByteCnt <= DATA_SIZE*2) // if ByteCnt less than DATA_SIZE + modbus_uart_buff[ind++] = modbus_msg->ByteCnt; + else // otherwise return data_size err + { + TrackerCnt_Err(hmodbus->rs_err); + return RS_COLLECT_MSG_ERR; + } + + //---------------DATA---------------- + //-----------[data bytes]------------ + uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->DATA; + for(int i = 0; i < modbus_msg->ByteCnt; i++) // filling buffer with data + { // set data + if (i%2 == 0) // HI byte + modbus_uart_buff[ind++] = (*tmp_data_addr)>>8; + else // LO byte + { + modbus_uart_buff[ind++] = *tmp_data_addr; + tmp_data_addr++; + } + } + + } + + } + else // if some error occur + { // send expection code + modbus_uart_buff[ind++] = modbus_msg->Except_Code; + } + } + if(ind < 0) + return RS_COLLECT_MSG_ERR; + + //---------------CRC---------------- + //---------[last 16 bytes]---------- + // calc crc of received data + uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind); + // write crc to message structure and modbus-uart buffer + modbus_msg->MB_CRC = CRC_VALUE; + modbus_uart_buff[ind++] = CRC_VALUE; + modbus_uart_buff[ind++] = CRC_VALUE >> 8; + + hmodbus->RS_Message_Size = ind; + + return RS_OK; // returns ok +} + +/** + * @brief Определить размер модбас запроса (СЛЕЙВ версия). + * @param hRS Указатель на хендлер RS. + * @param rx_data_size Указатель на переменную для записи кол-ва байт для принятия. + * @return RS_RES Статус о корректности рассчета кол-ва байт для принятия. + * @details Определение сколько байтов надо принять по протоколу. + */ +static int MB_Define_Size_of_Function(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) +{ + RS_StatusTypeDef MB_RES = 0; + int mb_func_size = 0; + + if (modbus_msg->Func_Code == MB_R_DIAGNOSTIC) + { + mb_func_size = 1; + } + else if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) + { + mb_func_size = 0; + } + else if ((modbus_msg->Func_Code & ~ERR_VALUES_START) < 0x0F) + { + mb_func_size = 1; + } + else + { + mb_func_size = modbus_msg->ByteCnt + 2; + } + + + mb_func_size = RX_FIRST_PART_SIZE + mb_func_size; // size of whole message + return mb_func_size; +} + + +/** + * @brief Парс сообщения в режиме слейв (фрейм мастера из uart -> msg). + * @param hmodbus Указатель на хендлер RS. + * @param modbus_msg Указатель на структуру сообщения. + * @param modbus_uart_buff Указатель на буффер UART. + * @return RS_RES Статус о результате заполнения структуры. + * @details Заполнение структуры сообщения из буффера UART. + */ +RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff) +{ + uint32_t check_empty_buff; + int ind = 0; // ind for modbus-uart buffer + hmodbus->f.RX_Continue = 0; + int expected_size = 0; + //-----INFO ABOUT DATA/MESSAGE------- + //-----------[first bits]------------ + // get ID of message/user + if(modbus_uart_buff[ind] != hmodbus->ID) + { + modbus_msg->MbAddr = 0; + ind++; + } + else + { + modbus_msg->MbAddr = modbus_uart_buff[ind++]; + } + + // get func code + modbus_msg->Func_Code = modbus_uart_buff[ind++]; + if(modbus_msg->Func_Code & ERR_VALUES_START) // явная херня + { + MB_Diagnostics_SlaveNAKCnt(); + modbus_msg->MbAddr = 0; + return RS_SKIP; + } + + if(modbus_msg->Func_Code == MB_R_DEVICE_INFO) // if it device identifications request + { + modbus_msg->DevId.MEI_Type = modbus_uart_buff[ind++]; + modbus_msg->DevId.ReadDevId = modbus_uart_buff[ind++]; + modbus_msg->DevId.NextObjId = modbus_uart_buff[ind++]; + modbus_msg->ByteCnt = 0; + } + else if(modbus_msg->Func_Code == MB_R_DIAGNOSTIC) + { + // Diagnostics: читаем 4 байта в DATA[0] и DATA[1] + // Sub-function + modbus_msg->DATA[0] = modbus_uart_buff[ind++] << 8; + modbus_msg->DATA[0] |= modbus_uart_buff[ind++]; + // Data + modbus_msg->DATA[1] = modbus_uart_buff[ind++] << 8; + modbus_msg->DATA[1] |= modbus_uart_buff[ind++]; + modbus_msg->Addr = 0; // не использует Addr + modbus_msg->Qnt = 0; // не использует Qnt + } + else // if its classic modbus request + { + // get address from CMD + modbus_msg->Addr = modbus_uart_buff[ind++] << 8; + modbus_msg->Addr |= modbus_uart_buff[ind++]; + + // get address from CMD + modbus_msg->Qnt = modbus_uart_buff[ind++] << 8; + modbus_msg->Qnt |= modbus_uart_buff[ind++]; + } + + if((hmodbus->pMessagePtr->Func_Code == 0x0F) || (hmodbus->pMessagePtr->Func_Code == 0x10)) + hmodbus->pMessagePtr->ByteCnt = modbus_uart_buff[ind++]; + else + hmodbus->pMessagePtr->ByteCnt = 0; + + expected_size = MB_Define_Size_of_Function(hmodbus, modbus_msg); + // если размер меньше ожидаемого - продолжаем принимать + if(hmodbus->RS_Message_Size < expected_size) + { + hmodbus->f.RX_Continue = 1; + return RS_SKIP; + } + // если больше Ошибка + else if (hmodbus->RS_Message_Size > expected_size) + { + MB_Diagnostics_CommunicationErrorCnt(); + return RS_PARSE_MSG_ERR; + } + + //---------------DATA---------------- + // (optional) + if (modbus_msg->ByteCnt != 0) + { + //check that data size is correct + if (modbus_msg->ByteCnt > DATA_SIZE*2) + { + TrackerCnt_Err(hmodbus->rs_err); + modbus_msg->Func_Code |= ERR_VALUES_START; + MB_Diagnostics_CommunicationErrorCnt(); + return RS_PARSE_MSG_ERR; + } + uint16_t *tmp_data_addr = (uint16_t *)modbus_msg->DATA; + for(int i = 0; i < modbus_msg->ByteCnt; i++) + { // set data + if (i%2 == 0) + *tmp_data_addr = ((uint16_t)modbus_uart_buff[ind++] << 8); + else + { + *tmp_data_addr |= modbus_uart_buff[ind++]; + tmp_data_addr++; + } + } + } + + //---------------CRC---------------- + //----------[last 16 bits]---------- + // calc crc of received data + uint16_t CRC_VALUE = crc16(modbus_uart_buff, ind); + // get crc of received data + modbus_msg->MB_CRC = modbus_uart_buff[ind++]; + modbus_msg->MB_CRC |= modbus_uart_buff[ind++] << 8; + // compare crc + if (modbus_msg->MB_CRC != CRC_VALUE) + { + MB_Diagnostics_CommunicationErrorCnt(); + TrackerCnt_Err(hmodbus->rs_err); + modbus_msg->Func_Code |= ERR_VALUES_START; + } + + return RS_OK; +} + +#else // MODBUS_ENABLE_SLAVE +RS_StatusTypeDef MB_Slave_Response(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg) {return RS_ERR;} +RS_StatusTypeDef MB_Slave_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff) {return RS_ERR;} +RS_StatusTypeDef MB_Slave_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff) {return RS_ERR;} +#endif \ No newline at end of file diff --git a/Modbus/Src/rs_message.c b/Modbus/Src/rs_message.c index d1133c6..d186530 100644 --- a/Modbus/Src/rs_message.c +++ b/Modbus/Src/rs_message.c @@ -23,6 +23,7 @@ - RS_TIM_Handler() в TIMx_IRQHandler вместо HAL_TIM_IRQHandler() ******************************************************************************/ #include "rs_message.h" +#include "modbus_diag.h" uint8_t RS_Buffer[MSG_SIZE_MAX]; // uart buffer @@ -34,7 +35,7 @@ extern void RS_TIM_DeInit(TIM_HandleTypeDef *htim); //------------------------------------------------------------------- //-------------------------GENERAL FUNCTIONS------------------------- /** - * @brief Start receive IT. + * @brief Начать прием по прерываниям. * @param hRS Указатель на хендлер RS. * @param RS_msg Указатель на структуру сообщения. * @return RS_RES Статус о состоянии RS после инициализации приема. @@ -60,7 +61,7 @@ RS_StatusTypeDef RS_Receive_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) // start receiving __HAL_UART_ENABLE_IT(hRS->huart, UART_IT_IDLE); - uart_res = HAL_UART_Receive_IT(hRS->huart, &hRS->pBufferPtr[hRS->RS_Message_Size], MSG_SIZE_MAX); // receive until ByteCnt+1 byte, + uart_res = HAL_UART_Receive_IT(hRS->huart, &hRS->pBufferPtr[hRS->RS_Message_Size], MSG_SIZE_MAX); // receive until ByteCnt+1 byte, // then in Callback restart receive for rest bytes // if receive isnt started - abort RS @@ -82,7 +83,7 @@ RS_StatusTypeDef RS_Receive_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) } /** - * @brief Start transmit IT. + * @brief Начать передачу по прерываниям. * @param hRS Указатель на хендлер RS. * @param RS_msg Указатель на структуру сообщения. * @return RS_RES Статус о состоянии RS после инициализации передачи. @@ -111,7 +112,6 @@ RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) //----------INITIALIZE TRANSMIT------------- RS_EnableTransmit(); -// for(int i = 0; i < hRS->sRS_Timeout; i++); RS_Set_Busy(hRS); // set RS busy RS_Set_TX_Flags(hRS); // initialize flags for transmit IT @@ -145,13 +145,13 @@ RS_StatusTypeDef RS_Transmit_IT(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) } /** - * @brief Initialize UART and handle RS stucture. + * @brief Инициалазация структуры @ref RS_HandleTypeDef. * @param hRS Указатель на хендлер RS. * @param suart Указатель на структуру с настройками UART. * @param stim Указатель на структуру с настройками таймера. * @param pRS_BufferPtr Указатель на буффер для приема-передачи по UART. Если он NULL, то поставиться библиотечный буфер. * @return RS_RES Статус о состоянии RS после инициализации. - * @note Инициализация перефирии и структуры для приема-передачи по RS. + * @details Инициализация перефирии и структуры для приема-передачи по RS. */ RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_HandleTypeDef *htim, uint8_t *pRS_BufferPtr) { @@ -166,9 +166,6 @@ RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_H hRS->htim = htim; - if (hRS->sRS_RX_Size_Mode == NULL) - return RS_ERR; - // check that buffer is defined if (hRS->pBufferPtr == NULL) { @@ -182,7 +179,7 @@ RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_H /** - * @brief Abort RS/UART. + * @brief Отменить прием/передачу RS/UART. * @param hRS Указатель на хендлер RS. * @param AbortMode Выбор, что надо отменить. - ABORT_TX: Отмена передачи по ЮАРТ, с очищением флагов TX, @@ -190,20 +187,14 @@ RS_StatusTypeDef RS_Init(RS_HandleTypeDef *hRS, UART_HandleTypeDef *huart, TIM_H - ABORT_RX_TX: Отмена приема и передачи по ЮАРТ, - ABORT_RS: Отмена приема-передачи RS, с очищением всей структуры. * @return RS_RES Статус о состоянии RS после аборта. - * @note Отмена работы UART в целом или отмена приема/передачи RS. - Также очищается хендл hRS. + * @details Отмена работы UART в целом или отмена приема/передачи RS. + Также очищается хендл hRS. */ RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode) { HAL_StatusTypeDef uart_res = 0; - if(hRS->htim) - { - if(hRS->sRS_Timeout) // if timeout setted - HAL_TIM_Base_Stop_IT(hRS->htim); // stop timeout - hRS->htim->Instance->CNT = 0; - __HAL_TIM_CLEAR_IT(hRS->htim, TIM_IT_UPDATE); - } + RS_Timeout_Stop(hRS); if((AbortMode&ABORT_RS) == 0x00) { @@ -237,11 +228,11 @@ RS_StatusTypeDef RS_Abort(RS_HandleTypeDef *hRS, RS_AbortTypeDef AbortMode) //------------------------------------------------------------------- //--------------------CALLBACK/HANDLER FUNCTIONS--------------------- /** - * @brief Handle for starting receive. + * @brief Обработчик для начала приема. * @param hRS Указатель на хендлер RS. * @param RS_msg Указатель на структуру сообщения. * @return RS_RES Статус о состоянии RS после инициализации приема или окончания общения. - * @note Определяет начинать прием команды/ответа или нет. + * @details Определяет начинать прием команды/ответа или нет. */ RS_StatusTypeDef RS_Handle_Receive_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) { @@ -249,9 +240,15 @@ RS_StatusTypeDef RS_Handle_Receive_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *R switch(hRS->sRS_Mode) { - case RS_SLAVE_ALWAYS_WAIT: // in slave mode with permanent waiting - RS_RES = RS_Receive_IT(hRS, RS_msg); break; // start receiving again - case RS_SLAVE_TIMEOUT_WAIT: // in slave mode with timeout waiting (start receiving cmd by request) + // В режиме мастер + case RS_MASTER_REQUEST: + RS_Timeout_Start(hRS); // сразу запускаем таймаут и начинаем прием + // В режиме слейв + case RS_SLAVE_ALWAYS_WAIT: + RS_RES = RS_Receive_IT(hRS, RS_msg); // Просто запускаем фоновый прием + break; + + case RS_RESERVED: RS_Set_Free(hRS); RS_RES = RS_OK; break; // end RS communication (set RS unbusy) } @@ -263,11 +260,11 @@ RS_StatusTypeDef RS_Handle_Receive_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *R return RS_RES; } /** - * @brief Handle for starting transmit. + * @brief Обработчик для начала передачи. * @param hRS Указатель на хендлер RS. * @param RS_msg Указатель на структуру сообщения. * @return RS_RES Статус о состоянии RS после инициализации передачи. - * @note Определяет отвечать ли на команду или нет. + * @details Определяет отвечать ли на команду или нет. */ RS_StatusTypeDef RS_Handle_Transmit_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) { @@ -276,13 +273,14 @@ RS_StatusTypeDef RS_Handle_Transmit_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef * switch(hRS->sRS_Mode) { case RS_SLAVE_ALWAYS_WAIT: // in slave mode always response - case RS_SLAVE_TIMEOUT_WAIT: // transmit response + case RS_RESERVED: // transmit response + case RS_MASTER_REQUEST: // transmit response RS_RES = RS_Transmit_IT(hRS, RS_msg); break; } if(RS_RES != RS_OK) { - if(hRS->sRS_Mode < RS_MASTER_START) + if(hRS->sRS_Mode < RS_MASTER_MODE_START) { RS_Handle_Receive_Start(hRS, RS_msg); } @@ -294,10 +292,10 @@ RS_StatusTypeDef RS_Handle_Transmit_Start(RS_HandleTypeDef *hRS, RS_MsgTypeDef * } /** - * @brief UART TX Callback: define behaviour after transmiting message. + * @brief UART TX Callback: коллбек после окончания передачи. * @param hRS Указатель на хендлер RS. * @return RS_RES Статус о состоянии RS после обработки приема. - * @note Определяет поведение RS после передачи сообщения. + * @details Определяет поведение RS после передачи сообщения. */ RS_StatusTypeDef RS_UART_TxCpltCallback(RS_HandleTypeDef *hRS) { @@ -306,24 +304,18 @@ RS_StatusTypeDef RS_UART_TxCpltCallback(RS_HandleTypeDef *hRS) //--------------ENDING TRANSMITTING------------- RS_Set_TX_End(hRS); - RS_EnableReceive(); -// for(int i = 0; i < hRS->sRS_Timeout; i++); //-----------START RECEIVING or END RS---------- RS_RES = RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); -// if(RS_RES != RS_OK) -// { -// __NOP(); -// } return RS_RES; } /** - * @brief Handler for UART. +* @brief Обработчик прерывания UART. * @param hRS Указатель на хендлер RS. - * @note Обрабатывает ошибки если есть и вызывает RS Коллбеки. - * Добавить вызов этой функции в UARTx_IRQHandler() после HAL_UART_IRQHandler(). + * @details Обрабатывает ошибки если есть и вызывает RS Коллбеки. + * Добавить вызов этой функции в UARTx_IRQHandler() ВМЕСТО HAL_UART_IRQHandler(). */ void RS_UART_Handler(RS_HandleTypeDef *hRS) { @@ -331,13 +323,14 @@ void RS_UART_Handler(RS_HandleTypeDef *hRS) { return; } - //-------------CHECK IDLE FLAG FIRST------------- + //-------------CHECK IDLE FLAG FIRST------------- /* Проверяем флаг IDLE в первую очередь - это гарантирует обработку только после idle */ if(__HAL_UART_GET_FLAG(hRS->huart, UART_FLAG_IDLE) && __HAL_UART_GET_IT_SOURCE(hRS->huart, UART_IT_IDLE)) { __HAL_UART_CLEAR_IDLEFLAG(hRS->huart); // Важно: очистить флаг IDLE //-------------STANDARD UART HANDLING------------- HAL_UART_IRQHandler(hRS->huart); + hRS->f.RX_Continue = 0; // Если прием активен и мы получили IDLE - это конец фрейма if(RS_Is_RX_Busy(hRS) && hRS->f.RX_Ongoing) @@ -356,29 +349,23 @@ void RS_UART_Handler(RS_HandleTypeDef *hRS) // Парсим наше сообщение RS_StatusTypeDef parse_res = RS_Parse_Message(hRS, hRS->pMessagePtr, hRS->pBufferPtr); - - // Проверяем адрес Modbus перед обработкой - if(hRS->pMessagePtr->MbAddr != hRS->ID) + + // Если сообещине принято корректно + if(parse_res == RS_OK) { - // Чужое сообщение - игнорируем и начинаем новый прием - RS_Abort(hRS, ABORT_RX); - RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); - return; - } - - - - // Если сообещине принято корректно - отвечаем на него - if(parse_res != RS_SKIP) - { - if(hRS->htim) - { - // Останавливаем таймаут - if(hRS->sRS_Timeout) - HAL_TIM_Base_Stop_IT(hRS->htim); - } + RS_Timeout_Stop(hRS); + hRS->lastPacketTick = uwTick; - RS_Response(hRS, hRS->pMessagePtr); + if(hRS->sRS_Mode < RS_MASTER_MODE_START) + RS_Response(hRS, hRS->pMessagePtr); // отвечаем на запрос + else + { + if(hRS->pCallback) + { + hRS->pCallback(hRS, hRS->pMessagePtr); // обрабатываем ответ + RS_Set_Free(hRS); // освобожднаем RS + } + } } else { @@ -399,19 +386,13 @@ void RS_UART_Handler(RS_HandleTypeDef *hRS) /* IF NO ERROR OCCURS */ if(hRS->huart->ErrorCode == 0) { - - if(hRS->htim) + + // if first byte is received and receive is active + if((hRS->huart->RxXferCount+1 == hRS->huart->RxXferSize) && RS_Is_RX_Busy(hRS)) { - hRS->htim->Instance->CNT = 0; // reset cnt; - /* Start timeout при получении первого байта */ - if(hRS->sRS_Timeout) // if timeout setted - if((hRS->huart->RxXferCount+1 == hRS->huart->RxXferSize) && RS_Is_RX_Busy(hRS)) // if first byte is received and receive is active - { - hRS->htim->Instance->ARR = hRS->sRS_Timeout; - HAL_TIM_Base_Start_IT(hRS->htim); - RS_Set_RX_Active_Flags(hRS); - } + RS_Timeout_Start(hRS); } + RS_Timeout_Update(hRS); /* RX Callback - теперь НЕ вызываем здесь, ждем IDLE */ @@ -425,6 +406,10 @@ void RS_UART_Handler(RS_HandleTypeDef *hRS) //----------------ERRORS HANDLER---------------- else { + if (hRS->huart->ErrorCode & HAL_UART_ERROR_ORE) + { + MB_Diagnostics_CharacterOverrunCnt(); // <-- Обнаружено переполнение + } //TrackerCnt_Err(hRS->rs_err); /* de-init uart transfer */ RS_Abort(hRS, ABORT_RS); @@ -436,10 +421,10 @@ void RS_UART_Handler(RS_HandleTypeDef *hRS) /** - * @brief Handler for TIM. + * @brief Обработчик прерывания TIM. * @param hRS Указатель на хендлер RS. - * @note Попадание сюда = таймаут и перезапуск RS приема - * Добавить вызов этой функции в TIMx_IRQHandler() после HAL_TIM_IRQHandler(). + * @details Попадание сюда = таймаут и перезапуск RS приема + * Добавить вызов этой функции в TIMx_IRQHandler() ВМЕСТО HAL_TIM_IRQHandler(). */ void RS_TIM_Handler(RS_HandleTypeDef *hRS) { @@ -449,13 +434,73 @@ void RS_TIM_Handler(RS_HandleTypeDef *hRS) } HAL_TIM_IRQHandler(hRS->htim); - RS_Abort(hRS, ABORT_RS); + RS_Abort(hRS, ABORT_RS); - if(hRS->pMessagePtr->MbAddr == hRS->ID) // ошибка если таймаут по нашему сообщению - TrackerCnt_Err(hRS->rs_err); + if(hRS->pMessagePtr->MbAddr == hRS->ID) // ошибка если таймаут по нашему сообщению + TrackerCnt_Err(hRS->rs_err); - RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); + if(hRS->sRS_Mode == RS_MASTER_REQUEST) { + // Мастер: таймаут ответа -> освобождаем для нового запроса + RS_Set_Free(hRS); + } else { + // Слейв: перезапускаем прием + RS_Handle_Receive_Start(hRS, hRS->pMessagePtr); + } } + +/** + * @brief Запуск таймаута приема. + * @param hRS Указатель на хендлер RS. + * @return RS_RES Статус операции. + * @details Запускает таймер для отсчета времени ожидания следующего байта. + */ +RS_StatusTypeDef RS_Timeout_Start(RS_HandleTypeDef *hRS) +{ + if(hRS->htim) + { + hRS->htim->Instance->CNT = 0; // reset cnt; + if(hRS->sRS_Timeout) // if timeout setted + { + hRS->htim->Instance->ARR = hRS->sRS_Timeout; + HAL_TIM_Base_Start_IT(hRS->htim); + RS_Set_RX_Active_Flags(hRS); + } + } + return RS_OK; +} +/** + * @brief Остановка таймаута приема. + * @param hRS Указатель на хендлер RS. + * @return RS_RES Статус операции. + * @details Останавливает таймер ожидания. + */ +RS_StatusTypeDef RS_Timeout_Stop(RS_HandleTypeDef *hRS) +{ + if(hRS->htim) + { + // Останавливаем таймаут + if(hRS->sRS_Timeout) + HAL_TIM_Base_Stop_IT(hRS->htim); + hRS->htim->Instance->CNT = 0; + __HAL_TIM_CLEAR_IT(hRS->htim, TIM_IT_UPDATE); + } + return RS_OK; +} +/** + * @brief Обновление (сброс) таймаута приема. + * @param hRS Указатель на хендлер RS. + * @return RS_RES Статус операции. + * @details Сбрасывает счетчик таймера в 0. + */ +RS_StatusTypeDef RS_Timeout_Update(RS_HandleTypeDef *hRS) +{ + if(hRS->htim) + { + hRS->htim->Instance->CNT = 0; // reset cnt; + } + return RS_OK; +} + //--------------------CALLBACK/HANDLER FUNCTIONS--------------------- //------------------------------------------------------------------- @@ -468,7 +513,6 @@ void RS_TIM_Handler(RS_HandleTypeDef *hRS) * @param hRS Указатель на хендлер RS. * @param RS_msg Указатель на структуру сообщения. * @return RS_RES Статус о результате ответа на комманду. - * @note Обработка принятой комманды и ответ на неё. */ __weak RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg) { @@ -477,12 +521,11 @@ __weak RS_StatusTypeDef RS_Response(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg } /** - * @brief Собрать сообщение в буфер UART. + * @brief Пользовательская функция для сбора сообщения в буфер UART. * @param hRS Указатель на хендлер RS. * @param RS_msg Указатель на структуру сообщения. * @param msg_uart_buff Указатель на буффер UART. * @return RS_RES Статус о результате заполнения буфера. - * @note Заполнение буффера UART из структуры сообщения. */ __weak RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff) { @@ -491,12 +534,11 @@ __weak RS_StatusTypeDef RS_Collect_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef } /** - * @brief Разпарсить сообщение из буфера UART. + * @brief Пользовательская функция для парса сообщения из буфера UART. * @param hRS Указатель на хендлер RS. * @param RS_msg Указатель на структуру сообщения. * @param msg_uart_buff Указатель на буффер UART. * @return RS_RES Статус о результате заполнения структуры. - * @note Заполнение структуры сообщения из буффера UART. */ __weak RS_StatusTypeDef RS_Parse_Message(RS_HandleTypeDef *hRS, RS_MsgTypeDef *RS_msg, uint8_t *msg_uart_buff) { diff --git a/STM32F103_Example/Core/Src/main.c b/STM32F103_Example/Core/Src/main.c index f32a1eb..aac0e0d 100644 --- a/STM32F103_Example/Core/Src/main.c +++ b/STM32F103_Example/Core/Src/main.c @@ -91,10 +91,16 @@ int main(void) MX_USART1_UART_Init(); MX_TIM3_Init(); /* USER CODE BEGIN 2 */ - MODBUS_SetupHardware(&hmodbus1, &huart1, &htim3); - RS_Receive_IT(&hmodbus1, &MODBUS_MSG); + MODBUS_FirstInit(&hmodbus1, &huart1, &htim3); +#ifdef MODBUS_MODE_MASTER + MODBUS_Config(&hmodbus1, 0, MODBUS_TIMEOUT, MODBUS_MODE_MASTER); + MODBUS_MSG = MB_REQUEST_READ_COILS(1, 0, 10); +#else + MODBUS_Config(&hmodbus1, MODBUS_DEVICE_ID, MODBUS_TIMEOUT, MODBUS_MODE_SLAVE); + MODBUS_SlaveStart(&hmodbus1, NULL); +#endif /* USER CODE END 2 */ - + /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) diff --git a/STM32F103_Example/MDK-ARM/Modbus_example.uvguix.wot89 b/STM32F103_Example/MDK-ARM/Modbus_example.uvguix.wot89 new file mode 100644 index 0000000..c08db89 --- /dev/null +++ b/STM32F103_Example/MDK-ARM/Modbus_example.uvguix.wot89 @@ -0,0 +1,1923 @@ + + + + -6.1 + +
### uVision Project, (C) Keil Software
+ + + E:\.WORK\STM32\STM32_Modbus\Modbus\Src + + + + + + + 38003 + Registers + 140 90 + + + 346 + Code Coverage + 1010 160 + + + 204 + Performance Analyzer + 1170 + + + + + + 35141 + Event Statistics + + 200 50 700 + + + 1506 + Symbols + + 80 80 80 + + + 1936 + Watch 1 + + 200 133 133 + + + 1937 + Watch 2 + + 200 133 133 + + + 1935 + Call Stack + Locals + + 200 133 133 + + + 2506 + Trace Data + + 75 135 130 95 70 230 200 150 + + + 466 + Source Browser + 500 + 300 + + + + + + + + 1 + 1 + 0 + 0 + -1 + + + + + + + 44 + 2 + 3 + + -1 + -1 + + + -1 + -1 + + + 84 + -33 + 777 + 873 + + + + 0 + + 668 + 0100000004000000010000000100000001000000010000000000000002000000000000000100000001000000000000002800000028000000010000000600000000000000010000003D453A5C2E574F524B5C53544D33325C53544D33325F4D6F646275735C53544D3332463130335F4578616D706C655C436F72655C5372635C6D61696E2E6300000000066D61696E2E6300000000C5D4F200FFFFFFFF2F453A5C2E574F524B5C53544D33325C53544D33325F4D6F646275735C4D6F646275735C5372635C6D6F646275732E6300000000086D6F646275732E6300000000FFDC7800FFFFFFFF34453A5C2E574F524B5C53544D33325C53544D33325F4D6F646275735C4D6F646275735C5372635C6D6F646275735F646174612E63000000000D6D6F646275735F646174612E6300000000BECEA100FFFFFFFF3D453A5C2E574F524B5C53544D33325C53544D33325F4D6F646275735C53544D3332463130335F4578616D706C655C436F72655C5372635C6770696F2E6300000000066770696F2E6300000000F0A0A100FFFFFFFF36453A5C2E574F524B5C53544D33325C53544D33325F4D6F646275735C4D6F646275735C496E635C6D6F646275735F636F6E6669672E68000000000F6D6F646275735F636F6E6669672E6800000000BCA8E100FFFFFFFF34453A5C2E574F524B5C53544D33325C53544D33325F4D6F646275735C4D6F646275735C496E635C6D6F646275735F636F72652E68000000000D6D6F646275735F636F72652E68000000009CC1B600FFFFFFFF0100000010000000C5D4F200FFDC7800BECEA100F0A0A100BCA8E1009CC1B600F7B88600D9ADC200A5C2D700B3A6BE00EAD6A300F6FA7D00B5E99D005FC3CF00C1838300CACAD500010000000000000002000000F4000000660000008007000080020000 + + + + 0 + Build + + -1 + -1 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + F40000004F00000090050000E5000000 + + + 16 + A4000000BB0000006C03000051010000 + + + + 1005 + 1005 + 1 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + 0300000066000000ED00000050020000 + + + 16 + A4000000BB000000940100008E010000 + + + + 109 + 109 + 1 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + 0300000066000000ED00000050020000 + + + 16 + A4000000BB000000C001000013030000 + + + + 1465 + 1465 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + 000000004502000090050000DB020000 + + + 16 + A4000000BB0000006C03000051010000 + + + + 1466 + 1466 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + 03000000480200008D050000AE020000 + + + 16 + A4000000BB0000006C03000051010000 + + + + 1467 + 1467 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + 03000000480200008D050000AE020000 + + + 16 + A4000000BB0000006C03000051010000 + + + + 1468 + 1468 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + 03000000480200008D050000AE020000 + + + 16 + A4000000BB0000006C03000051010000 + + + + 1506 + 1506 + 0 + 0 + 0 + 0 + 32767 + 0 + 16384 + 0 + + 16 + A3040000660000008D05000009010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 1913 + 1913 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + F7000000660000008D050000CC000000 + + + 16 + A4000000BB0000006C03000051010000 + + + + 1935 + 1935 + 0 + 0 + 0 + 0 + 32767 + 0 + 32768 + 0 + + 16 + 03000000480200008D050000C2020000 + + + 16 + A4000000BB000000940100008E010000 + + + + 1936 + 1936 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + 03000000480200008D050000AE020000 + + + 16 + A4000000BB000000940100008E010000 + + + + 1937 + 1937 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + 03000000480200008D050000AE020000 + + + 16 + A4000000BB000000940100008E010000 + + + + 1939 + 1939 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + 03000000480200008D050000AE020000 + + + 16 + A4000000BB0000006C03000051010000 + + + + 1940 + 1940 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + 03000000480200008D050000AE020000 + + + 16 + A4000000BB0000006C03000051010000 + + + + 1941 + 1941 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + 03000000480200008D050000AE020000 + + + 16 + A4000000BB0000006C03000051010000 + + + + 1942 + 1942 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + 03000000480200008D050000AE020000 + + + 16 + A4000000BB0000006C03000051010000 + + + + 195 + 195 + 1 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + 0300000066000000ED00000050020000 + + + 16 + A4000000BB000000C001000013030000 + + + + 196 + 196 + 1 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + 0300000066000000ED00000050020000 + + + 16 + A4000000BB000000C001000013030000 + + + + 197 + 197 + 1 + 0 + 0 + 0 + 32767 + 0 + 32768 + 0 + + 16 + 03000000840200007D070000F5030000 + + + 16 + A4000000BB0000006C03000051010000 + + + + 198 + 198 + 0 + 0 + 0 + 0 + 32767 + 0 + 32768 + 0 + + 16 + 000000003102000090050000DB020000 + + + 16 + A4000000BB0000006C03000051010000 + + + + 199 + 199 + 1 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + 03000000840200007D070000F5030000 + + + 16 + A4000000BB0000006C03000051010000 + + + + 203 + 203 + 0 + 0 + 0 + 0 + 32767 + 0 + 8192 + 0 + + 16 + F40000006300000090050000E5000000 + + + 16 + A4000000BB0000006C03000051010000 + + + + 204 + 204 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + F7000000660000008D050000CC000000 + + + 16 + A4000000BB0000006C03000051010000 + + + + 221 + 221 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + 00000000000000000000000000000000 + + + 16 + 0A0000000A0000006E0000006E000000 + + + + 2506 + 2506 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A0040000630000009005000041020000 + + + 16 + A4000000BB000000940100008E010000 + + + + 2507 + 2507 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + 000000004502000090050000C7020000 + + + 16 + A4000000BB0000006C03000051010000 + + + + 343 + 343 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + F7000000660000008D050000CC000000 + + + 16 + A4000000BB0000006C03000051010000 + + + + 346 + 346 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + F7000000660000008D050000CC000000 + + + 16 + A4000000BB0000006C03000051010000 + + + + 35141 + 35141 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + F40000006300000090050000E5000000 + + + 16 + A4000000BB000000940100008E010000 + + + + 35824 + 35824 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + F7000000660000008D050000CC000000 + + + 16 + A4000000BB0000006C03000051010000 + + + + 35885 + 35885 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 35886 + 35886 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 35887 + 35887 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 35888 + 35888 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 35889 + 35889 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 35890 + 35890 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 35891 + 35891 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 35892 + 35892 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 35893 + 35893 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 35894 + 35894 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 35895 + 35895 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 35896 + 35896 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 35897 + 35897 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 35898 + 35898 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 35899 + 35899 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 35900 + 35900 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 35901 + 35901 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 35902 + 35902 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 35903 + 35903 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 35904 + 35904 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 35905 + 35905 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 38003 + 38003 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + 0300000066000000ED000000C2020000 + + + 16 + A4000000BB000000C001000013030000 + + + + 38007 + 38007 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + 00000000810200009005000003030000 + + + 16 + A4000000BB0000006C03000051010000 + + + + 436 + 436 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + 03000000840200008D050000EA020000 + + + 16 + A4000000BB000000C001000013030000 + + + + 437 + 437 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + 03000000480200008D050000AE020000 + + + 16 + A4000000BB000000940100008E010000 + + + + 440 + 440 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + 03000000480200008D050000AE020000 + + + 16 + A4000000BB000000940100008E010000 + + + + 463 + 463 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + 03000000840200008D050000EA020000 + + + 16 + A4000000BB000000C001000013030000 + + + + 466 + 466 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + 03000000840200008D050000EA020000 + + + 16 + A4000000BB000000C001000013030000 + + + + 470 + 470 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + F7000000660000008D050000CC000000 + + + 16 + A4000000BB0000006C03000051010000 + + + + 50000 + 50000 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 50001 + 50001 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 50002 + 50002 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 50003 + 50003 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 50004 + 50004 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 50005 + 50005 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 50006 + 50006 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 50007 + 50007 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 50008 + 50008 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 50009 + 50009 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 50010 + 50010 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 50011 + 50011 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 50012 + 50012 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 50013 + 50013 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 50014 + 50014 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 50015 + 50015 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 50016 + 50016 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 50017 + 50017 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 50018 + 50018 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 50019 + 50019 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + A3040000660000008D0500008E010000 + + + 16 + A4000000BB000000940100008E010000 + + + + 59392 + 59392 + 1 + 0 + 0 + 0 + 32767 + 0 + 8192 + 0 + + 16 + 0000000000000000D10300001C000000 + + + 16 + 0A0000000A0000006E0000006E000000 + + + + 59393 + 0 + 1 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + 000000000E0400008007000021040000 + + + 16 + 0A0000000A0000006E0000006E000000 + + + + 59399 + 59399 + 1 + 0 + 0 + 0 + 32767 + 0 + 8192 + 1 + + 16 + 000000001C000000E701000038000000 + + + 16 + 0A0000000A0000006E0000006E000000 + + + + 59400 + 59400 + 0 + 0 + 0 + 0 + 32767 + 0 + 8192 + 2 + + 16 + 00000000380000006F02000054000000 + + + 16 + 0A0000000A0000006E0000006E000000 + + + + 824 + 824 + 0 + 0 + 0 + 0 + 32767 + 0 + 4096 + 0 + + 16 + 03000000480200008D050000AE020000 + + + 16 + A4000000BB000000940100008E010000 + + + + 3312 + 000000000B000000000000000020000000000000FFFFFFFFFFFFFFFFF4000000E500000090050000E9000000000000000100001004000000010000000000000000000000FFFFFFFF08000000CB00000057010000CC000000F08B00005A01000079070000D601000045890000FFFF02000B004354616262656450616E650020000000000000A4000000BB0000006C03000051010000F40000004F00000090050000E50000000000000040280046080000000B446973617373656D626C7900000000CB00000001000000FFFFFFFFFFFFFFFF14506572666F726D616E636520416E616C797A6572000000005701000001000000FFFFFFFFFFFFFFFF14506572666F726D616E636520416E616C797A657200000000CC00000001000000FFFFFFFFFFFFFFFF0E4C6F67696320416E616C797A657200000000F08B000001000000FFFFFFFFFFFFFFFF0D436F646520436F766572616765000000005A01000001000000FFFFFFFFFFFFFFFF11496E737472756374696F6E205472616365000000007907000001000000FFFFFFFFFFFFFFFF0F53797374656D20416E616C797A657200000000D601000001000000FFFFFFFFFFFFFFFF104576656E742053746174697374696373000000004589000001000000FFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000000000000001000000FFFFFFFFCB00000001000000FFFFFFFFCB000000000000000040000000000000FFFFFFFFFFFFFFFF9C0400004F000000A004000041020000000000000200001004000000010000000000000000000000FFFFFFFF2B000000E2050000CA0900002D8C00002E8C00002F8C0000308C0000318C0000328C0000338C0000348C0000358C0000368C0000378C0000388C0000398C00003A8C00003B8C00003C8C00003D8C00003E8C00003F8C0000408C0000418C000050C3000051C3000052C3000053C3000054C3000055C3000056C3000057C3000058C3000059C300005AC300005BC300005CC300005DC300005EC300005FC3000060C3000061C3000062C3000063C3000001800040000000000000A4000000BB000000940100008E010000A00400004F000000900500004102000000000000404100462B0000000753796D626F6C7300000000E205000001000000FFFFFFFFFFFFFFFF0A5472616365204461746100000000CA09000001000000FFFFFFFFFFFFFFFF00000000002D8C000001000000FFFFFFFFFFFFFFFF00000000002E8C000001000000FFFFFFFFFFFFFFFF00000000002F8C000001000000FFFFFFFFFFFFFFFF0000000000308C000001000000FFFFFFFFFFFFFFFF0000000000318C000001000000FFFFFFFFFFFFFFFF0000000000328C000001000000FFFFFFFFFFFFFFFF0000000000338C000001000000FFFFFFFFFFFFFFFF0000000000348C000001000000FFFFFFFFFFFFFFFF0000000000358C000001000000FFFFFFFFFFFFFFFF0000000000368C000001000000FFFFFFFFFFFFFFFF0000000000378C000001000000FFFFFFFFFFFFFFFF0000000000388C000001000000FFFFFFFFFFFFFFFF0000000000398C000001000000FFFFFFFFFFFFFFFF00000000003A8C000001000000FFFFFFFFFFFFFFFF00000000003B8C000001000000FFFFFFFFFFFFFFFF00000000003C8C000001000000FFFFFFFFFFFFFFFF00000000003D8C000001000000FFFFFFFFFFFFFFFF00000000003E8C000001000000FFFFFFFFFFFFFFFF00000000003F8C000001000000FFFFFFFFFFFFFFFF0000000000408C000001000000FFFFFFFFFFFFFFFF0000000000418C000001000000FFFFFFFFFFFFFFFF000000000050C3000001000000FFFFFFFFFFFFFFFF000000000051C3000001000000FFFFFFFFFFFFFFFF000000000052C3000001000000FFFFFFFFFFFFFFFF000000000053C3000001000000FFFFFFFFFFFFFFFF000000000054C3000001000000FFFFFFFFFFFFFFFF000000000055C3000001000000FFFFFFFFFFFFFFFF000000000056C3000001000000FFFFFFFFFFFFFFFF000000000057C3000001000000FFFFFFFFFFFFFFFF000000000058C3000001000000FFFFFFFFFFFFFFFF000000000059C3000001000000FFFFFFFFFFFFFFFF00000000005AC3000001000000FFFFFFFFFFFFFFFF00000000005BC3000001000000FFFFFFFFFFFFFFFF00000000005CC3000001000000FFFFFFFFFFFFFFFF00000000005DC3000001000000FFFFFFFFFFFFFFFF00000000005EC3000001000000FFFFFFFFFFFFFFFF00000000005FC3000001000000FFFFFFFFFFFFFFFF000000000060C3000001000000FFFFFFFFFFFFFFFF000000000061C3000001000000FFFFFFFFFFFFFFFF000000000062C3000001000000FFFFFFFFFFFFFFFF000000000063C3000001000000FFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000000000000001000000FFFFFFFFE205000001000000FFFFFFFFE2050000000000000010000001000000FFFFFFFFFFFFFFFFF00000004F000000F400000069020000010000000200001004000000010000000000000000000000FFFFFFFF05000000ED0300006D000000C3000000C40000007394000001800010000001000000A4000000BB000000940100008E010000000000004F000000F0000000690200000000000040410056050000000750726F6A65637401000000ED03000001000000FFFFFFFFFFFFFFFF05426F6F6B73010000006D00000001000000FFFFFFFFFFFFFFFF0946756E6374696F6E7301000000C300000001000000FFFFFFFFFFFFFFFF0954656D706C6174657301000000C400000001000000FFFFFFFFFFFFFFFF09526567697374657273000000007394000001000000FFFFFFFFFFFFFFFF00000000000000000000000000000000000000000000000001000000FFFFFFFFED03000001000000FFFFFFFFED030000000000000080000000000000FFFFFFFFFFFFFFFF000000002D020000900500003102000000000000010000100400000001000000000000000000000000000000000000000000000001000000C6000000FFFFFFFF0F0000008F070000930700009407000095070000960700009007000091070000B5010000B801000038030000B9050000BA050000BB050000BC050000CB09000001800080000000000000A4000000BB000000940100008E010000000000003102000090050000DB02000000000000404100460F0000001343616C6C20537461636B202B204C6F63616C73000000008F07000001000000FFFFFFFFFFFFFFFF0755415254202331000000009307000001000000FFFFFFFFFFFFFFFF0755415254202332000000009407000001000000FFFFFFFFFFFFFFFF0755415254202333000000009507000001000000FFFFFFFFFFFFFFFF15446562756720287072696E74662920566965776572000000009607000001000000FFFFFFFFFFFFFFFF0757617463682031000000009007000001000000FFFFFFFFFFFFFFFF0757617463682032000000009107000001000000FFFFFFFFFFFFFFFF10547261636520457863657074696F6E7300000000B501000001000000FFFFFFFFFFFFFFFF0E4576656E7420436F756E7465727300000000B801000001000000FFFFFFFFFFFFFFFF09554C494E4B706C7573000000003803000001000000FFFFFFFFFFFFFFFF084D656D6F7279203100000000B905000001000000FFFFFFFFFFFFFFFF084D656D6F7279203200000000BA05000001000000FFFFFFFFFFFFFFFF084D656D6F7279203300000000BB05000001000000FFFFFFFFFFFFFFFF084D656D6F7279203400000000BC05000001000000FFFFFFFFFFFFFFFF105472616365204E617669676174696F6E00000000CB09000001000000FFFFFFFFFFFFFFFFFFFFFFFF0000000001000000000000000000000001000000FFFFFFFFC802000031020000CC020000DB02000000000000020000000400000000000000000000000000000000000000000000000000000002000000C6000000FFFFFFFF8F07000001000000FFFFFFFF8F07000001000000C6000000000000000080000001000000FFFFFFFFFFFFFFFF0000000069020000800700006D02000001000000010000100400000001000000E0FCFFFF94000000FFFFFFFF06000000C5000000C7000000B4010000D2010000CF0100007794000001800080000001000000A4000000BB0000006C03000051010000000000006D020000800700000E0400000000000040820056060000000C4275696C64204F757470757401000000C500000001000000FFFFFFFFFFFFFFFF0D46696E6420496E2046696C657301000000C700000001000000FFFFFFFFFFFFFFFF0A4572726F72204C69737400000000B401000001000000FFFFFFFFFFFFFFFF0E536F757263652042726F7773657200000000D201000001000000FFFFFFFFFFFFFFFF0E416C6C205265666572656E63657300000000CF01000001000000FFFFFFFFFFFFFFFF0742726F77736572000000007794000001000000FFFFFFFFFFFFFFFF00000000000000000000000000000000000000000000000001000000FFFFFFFFC500000001000000FFFFFFFFC5000000000000000000000000000000 + + + 59392 + File + + 2612 + 00200000010000002800FFFF01001100434D4643546F6F6C426172427574746F6E00E100000000000000000000000000000000000000000000000100000001000000018001E100000000000001000000000000000000000000000000000100000001000000018003E1000000000000020000000000000000000000000000000001000000010000000180CD7F0000000000000300000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF000000000000000000000000000100000001000000018023E100000000040004000000000000000000000000000000000100000001000000018022E100000000040005000000000000000000000000000000000100000001000000018025E10000000000000600000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF00000000000000000000000000010000000100000001802BE10000000000000700000000000000000000000000000000010000000100000001802CE10000000004000800000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF00000000000000000000000000010000000100000001807A8A0000000000000900000000000000000000000000000000010000000100000001807B8A0000000004000A00000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180D3B00000000000000B000000000000000000000000000000000100000001000000018015B10000000004000C0000000000000000000000000000000001000000010000000180F4B00000000004000D000000000000000000000000000000000100000001000000018036B10000000004000E00000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180FF88000000000400460000000000000000000000000000000001000000010000000180FE880000000004004500000000000000000000000000000000010000000100000001800B810000000004001300000000000000000000000000000000010000000100000001800C810000000004001400000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180F0880000020000000F000000000000000000000000000000000100000001000000FFFF0100120043555646696E64436F6D626F427574746F6EE803000000000000000000000000000000000000000000000001000000010000009600000002002050000000000B52535F5365745F4672656596000000000000000300124D425F446961676E6F7374696373496E69740B52535F5365745F46726565144D4F444255535F4D617374657252657175657374000000000000000000000000018024E10000000000001100000000000000000000000000000000010000000100000001800A810000000000001200000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF000000000000000000000000000100000001000000FFFF01001500434D4643546F6F6C4261724D656E75427574746F6E2280000002000000150000002153746172742F53746F70202644656275672053657373696F6E094374726C2B46350000000000000000000000000100000001000000000000000000000001000000020021802280000000000000150000002153746172742F53746F70202644656275672053657373696F6E094374726C2B4635000000000000000000000000010000000100000000000000000000000100000000002180E0010000000000007500000021456E65726779204D6561737572656D656E742026776974686F75742044656275670000000000000000000000000100000001000000000000000000000001000000000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180C488000000000000160000000000000000000000000000000001000000010000000180C988000000000400180000000000000000000000000000000001000000010000000180C788000000000000190000000000000000000000000000000001000000010000002180C8880000000000001700000027264B696C6C20416C6C20427265616B706F696E747320696E2043757272656E7420546172676574000000000000000000000000010000000100000000000000000000000100000003002180C8880000000000001700000027264B696C6C20416C6C20427265616B706F696E747320696E2043757272656E7420546172676574000000000000000000000000010000000100000000000000000000000100000000002180E50100000000000078000000264B696C6C20416C6C20427265616B706F696E747320696E204163746976652050726F6A656374000000000000000000000000010000000100000000000000000000000100000000002180E601000000000000790000002F4B696C6C20416C6C20427265616B706F696E747320696E204D756C74692D50726F6A65637420576F726B73706163650000000000000000000000000100000001000000000000000000000001000000000001800000000001000000FFFFFFFF00000000000000000000000000010000000100000021804C010000020001001A0000000F2650726F6A6563742057696E646F77000000000000000000000000010000000100000000000000000000000100000008002180DD880000000000001A0000000750726F6A656374000000000000000000000000010000000100000000000000000000000100000000002180DC8B0000000000003A00000005426F6F6B73000000000000000000000000010000000100000000000000000000000100000000002180E18B0000000000003B0000000946756E6374696F6E73000000000000000000000000010000000100000000000000000000000100000000002180E28B000000000000400000000954656D706C6174657300000000000000000000000001000000010000000000000000000000010000000000218018890000000000003D0000000E536F757263652042726F777365720000000000000000000000000100000001000000000000000000000001000000000021800000000000000400FFFFFFFF00000000000000000000000000010000000100000000000000000000000100000000002180D988000000000000390000000C4275696C64204F7574707574000000000000000000000000010000000100000000000000000000000100000000002180E38B000000000000410000000B46696E64204F75747075740000000000000000000000000100000001000000000000000000000001000000000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180FB7F0000000000001B000000000000000000000000000000000100000001000000000000000446696C65FF7F0000 + + + 1423 + 2800FFFF01001100434D4643546F6F6C426172427574746F6E00E1000000000000FFFFFFFF000100000000000000010000000000000001000000018001E1000000000000FFFFFFFF000100000000000000010000000000000001000000018003E1000000000000FFFFFFFF0001000000000000000100000000000000010000000180CD7F000000000000FFFFFFFF00010000000000000001000000000000000100000001800000000000000000FFFFFFFF000000000000000000010000000000000001000000018023E1000000000000FFFFFFFF000100000000000000010000000000000001000000018022E1000000000000FFFFFFFF000100000000000000010000000000000001000000018025E1000000000000FFFFFFFF00010000000000000001000000000000000100000001800000000000000000FFFFFFFF00000000000000000001000000000000000100000001802BE1000000000000FFFFFFFF00010000000000000001000000000000000100000001802CE1000000000000FFFFFFFF00010000000000000001000000000000000100000001800000000000000000FFFFFFFF00000000000000000001000000000000000100000001807A8A000000000000FFFFFFFF00010000000000000001000000000000000100000001807B8A000000000000FFFFFFFF00010000000000000001000000000000000100000001800000000000000000FFFFFFFF0000000000000000000100000000000000010000000180D3B0000000000000FFFFFFFF000100000000000000010000000000000001000000018015B1000000000000FFFFFFFF0001000000000000000100000000000000010000000180F4B0000000000000FFFFFFFF000100000000000000010000000000000001000000018036B1000000000000FFFFFFFF00010000000000000001000000000000000100000001800000000000000000FFFFFFFF0000000000000000000100000000000000010000000180FF88000000000000FFFFFFFF0001000000000000000100000000000000010000000180FE88000000000000FFFFFFFF00010000000000000001000000000000000100000001800B81000000000000FFFFFFFF00010000000000000001000000000000000100000001800C81000000000000FFFFFFFF00010000000000000001000000000000000100000001800000000000000000FFFFFFFF0000000000000000000100000000000000010000000180F088000000000000FFFFFFFF0001000000000000000100000000000000010000000180EE7F000000000000FFFFFFFF000100000000000000010000000000000001000000018024E1000000000000FFFFFFFF00010000000000000001000000000000000100000001800A81000000000000FFFFFFFF00010000000000000001000000000000000100000001800000000000000000FFFFFFFF00000000000000000001000000000000000100000001802280000000000000FFFFFFFF00010000000000000001000000000000000100000001800000000000000000FFFFFFFF0000000000000000000100000000000000010000000180C488000000000000FFFFFFFF0001000000000000000100000000000000010000000180C988000000000000FFFFFFFF0001000000000000000100000000000000010000000180C788000000000000FFFFFFFF0001000000000000000100000000000000010000000180C888000000000000FFFFFFFF00010000000000000001000000000000000100000001800000000000000000FFFFFFFF0000000000000000000100000000000000010000000180DD88000000000000FFFFFFFF00010000000000000001000000000000000100000001800000000000000000FFFFFFFF0000000000000000000100000000000000010000000180FB7F000000000000FFFFFFFF000100000000000000010000000000000001000000 + + + 1423 + 2800FFFF01001100434D4643546F6F6C426172427574746F6E00E100000000000000000000000000000000000000000000000100000001000000018001E100000000000001000000000000000000000000000000000100000001000000018003E1000000000000020000000000000000000000000000000001000000010000000180CD7F0000000000000300000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF000000000000000000000000000100000001000000018023E100000000000004000000000000000000000000000000000100000001000000018022E100000000000005000000000000000000000000000000000100000001000000018025E10000000000000600000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF00000000000000000000000000010000000100000001802BE10000000000000700000000000000000000000000000000010000000100000001802CE10000000000000800000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF00000000000000000000000000010000000100000001807A8A0000000000000900000000000000000000000000000000010000000100000001807B8A0000000000000A00000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180D3B00000000000000B000000000000000000000000000000000100000001000000018015B10000000000000C0000000000000000000000000000000001000000010000000180F4B00000000000000D000000000000000000000000000000000100000001000000018036B10000000000000E00000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180FF880000000000000F0000000000000000000000000000000001000000010000000180FE880000000000001000000000000000000000000000000000010000000100000001800B810000000000001100000000000000000000000000000000010000000100000001800C810000000000001200000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180F088000000000000130000000000000000000000000000000001000000010000000180EE7F00000000000014000000000000000000000000000000000100000001000000018024E10000000000001500000000000000000000000000000000010000000100000001800A810000000000001600000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF000000000000000000000000000100000001000000018022800000000000001700000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180C488000000000000180000000000000000000000000000000001000000010000000180C988000000000000190000000000000000000000000000000001000000010000000180C7880000000000001A0000000000000000000000000000000001000000010000000180C8880000000000001B00000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180DD880000000000001C00000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180FB7F0000000000001D000000000000000000000000000000000100000001000000 + + + + 59399 + Build + + 988 + 00200000010000001000FFFF01001100434D4643546F6F6C426172427574746F6ECF7F0000000000001C0000000000000000000000000000000001000000010000000180D07F0000000000001D000000000000000000000000000000000100000001000000018030800000000000001E000000000000000000000000000000000100000001000000FFFF01001500434D4643546F6F6C4261724D656E75427574746F6EC7040000000000006A0000000C4261746368204275696C2664000000000000000000000000010000000100000000000000000000000100000004000580C7040000000000006A0000000C4261746368204275696C266400000000000000000000000001000000010000000000000000000000010000000000058046070000000000006B0000000D42617463682052656275696C640000000000000000000000000100000001000000000000000000000001000000000005804707000000000000FFFFFFFF0B426174636820436C65616E0100000000000000000000000100000001000000000000000000000001000000000005809E8A0000000000001F0000000F4261746326682053657475702E2E2E000000000000000000000000010000000100000000000000000000000100000000000180D17F0000000004002000000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF00000000000000000000000000010000000100000001804C8A0000000000002100000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF000000000000000000000000000100000001000000FFFF01001900434D4643546F6F6C426172436F6D626F426F78427574746F6EBA00000000000000000000000000000000000000000000000001000000010000009600000003002050000000000E4D6F646275735F6578616D706C65960000000000000001000E4D6F646275735F6578616D706C65000000000180EB880000000000002200000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180C07F000000000000230000000000000000000000000000000001000000010000000180B08A000000000400240000000000000000000000000000000001000000010000000180A8010000000000004E00000000000000000000000000000000010000000100000001807202000000000000530000000000000000000000000000000001000000010000000180BE010000000000005000000000000000000000000000000000010000000100000000000000054275696C64FF7F0000 + + + 583 + 1000FFFF01001100434D4643546F6F6C426172427574746F6ECF7F000000000000FFFFFFFF0001000000000000000100000000000000010000000180D07F000000000000FFFFFFFF00010000000000000001000000000000000100000001803080000000000000FFFFFFFF00010000000000000001000000000000000100000001809E8A000000000000FFFFFFFF0001000000000000000100000000000000010000000180D17F000000000000FFFFFFFF00010000000000000001000000000000000100000001800000000000000000FFFFFFFF00000000000000000001000000000000000100000001804C8A000000000000FFFFFFFF00010000000000000001000000000000000100000001800000000000000000FFFFFFFF00000000000000000001000000000000000100000001806680000000000000FFFFFFFF0001000000000000000100000000000000010000000180EB88000000000000FFFFFFFF00010000000000000001000000000000000100000001800000000000000000FFFFFFFF0000000000000000000100000000000000010000000180C07F000000000000FFFFFFFF0001000000000000000100000000000000010000000180B08A000000000000FFFFFFFF0001000000000000000100000000000000010000000180A801000000000000FFFFFFFF00010000000000000001000000000000000100000001807202000000000000FFFFFFFF0001000000000000000100000000000000010000000180BE01000000000000FFFFFFFF000100000000000000010000000000000001000000 + + + 583 + 1000FFFF01001100434D4643546F6F6C426172427574746F6ECF7F000000000000000000000000000000000000000000000001000000010000000180D07F00000000000001000000000000000000000000000000000100000001000000018030800000000000000200000000000000000000000000000000010000000100000001809E8A000000000000030000000000000000000000000000000001000000010000000180D17F0000000000000400000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF00000000000000000000000000010000000100000001804C8A0000000000000500000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF00000000000000000000000000010000000100000001806680000000000000060000000000000000000000000000000001000000010000000180EB880000000000000700000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180C07F000000000000080000000000000000000000000000000001000000010000000180B08A000000000000090000000000000000000000000000000001000000010000000180A8010000000000000A000000000000000000000000000000000100000001000000018072020000000000000B0000000000000000000000000000000001000000010000000180BE010000000000000C000000000000000000000000000000000100000001000000 + + + + 59400 + Debug + + 2373 + 00200000000000001900FFFF01001100434D4643546F6F6C426172427574746F6ECC880000000000002500000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF000000000000000000000000000100000001000000018017800000000000002600000000000000000000000000000000010000000100000001801D800000000000002700000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF00000000000000000000000000010000000100000001801A800000000000002800000000000000000000000000000000010000000100000001801B80000000000000290000000000000000000000000000000001000000010000000180E57F0000000000002A00000000000000000000000000000000010000000100000001801C800000000000002B00000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF000000000000000000000000000100000001000000018000890000000000002C00000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180E48B0000000000002D0000000000000000000000000000000001000000010000000180F07F0000000000002E0000000000000000000000000000000001000000010000000180E8880000000000003700000000000000000000000000000000010000000100000001803B010000000000002F0000000000000000000000000000000001000000010000000180BB8A00000000000030000000000000000000000000000000000100000001000000FFFF01001500434D4643546F6F6C4261724D656E75427574746F6E0E01000000000000310000000D57617463682057696E646F7773000000000000000000000000010000000100000000000000000000000100000003001380D88B00000000000031000000085761746368202631000000000000000000000000010000000100000000000000000000000100000000001380D98B00000000000031000000085761746368202632000000000000000000000000010000000100000000000000000000000100000000001380CE01000000000000FFFFFFFF0C576174636820416E63686F720100000000000000000000000100000001000000000000000000000001000000000013800F01000000000000320000000E4D656D6F72792057696E646F7773000000000000000000000000010000000100000000000000000000000100000004001380D28B00000000000032000000094D656D6F7279202631000000000000000000000000010000000100000000000000000000000100000000001380D38B00000000000032000000094D656D6F7279202632000000000000000000000000010000000100000000000000000000000100000000001380D48B00000000000032000000094D656D6F7279202633000000000000000000000000010000000100000000000000000000000100000000001380D58B00000000000032000000094D656D6F72792026340000000000000000000000000100000001000000000000000000000001000000000013801001000000000000330000000E53657269616C2057696E646F77730000000000000000000000000100000001000000000000000000000001000000040013809307000000000000330000000855415254202326310000000000000000000000000100000001000000000000000000000001000000000013809407000000000000330000000855415254202326320000000000000000000000000100000001000000000000000000000001000000000013809507000000000000330000000855415254202326330000000000000000000000000100000001000000000000000000000001000000000013809607000000000000330000001626446562756720287072696E746629205669657765720000000000000000000000000100000001000000000000000000000001000000000013803C010000000000007200000010416E616C797369732057696E646F7773000000000000000000000000010000000100000000000000000000000100000004001380658A000000000000340000000F264C6F67696320416E616C797A6572000000000000000000000000010000000100000000000000000000000100000000001380DC7F0000000000003E0000001526506572666F726D616E636520416E616C797A6572000000000000000000000000010000000100000000000000000000000100000000001380E788000000000000380000000E26436F646520436F766572616765000000000000000000000000010000000100000000000000000000000100000000001380CD01000000000000FFFFFFFF0F416E616C7973697320416E63686F7201000000000000000000000001000000010000000000000000000000010000000000138053010000000000003F0000000D54726163652057696E646F77730000000000000000000000000100000001000000000000000000000001000000010013805401000000000000FFFFFFFF115472616365204D656E7520416E63686F720100000000000000000000000100000001000000000000000000000001000000000013802901000000000000350000001553797374656D205669657765722057696E646F77730000000000000000000000000100000001000000000000000000000001000000010013804B01000000000000FFFFFFFF1453797374656D2056696577657220416E63686F720100000000000000000000000100000001000000000000000000000001000000000001800000000001000000FFFFFFFF00000000000000000000000000010000000100000013800189000000000000360000000F26546F6F6C626F782057696E646F7700000000000000000000000001000000010000000000000000000000010000000300138044C5000000000000FFFFFFFF0E5570646174652057696E646F77730100000000000000000000000100000001000000000000000000000001000000000013800000000000000400FFFFFFFF000000000000000000000000000100000001000000000000000000000001000000000013805B01000000000000FFFFFFFF12546F6F6C626F78204D656E75416E63686F720100000000000000000000000100000001000000000000000000000001000000000000000000054465627567FF7F0000 + + + 898 + 1900FFFF01001100434D4643546F6F6C426172427574746F6ECC88000000000000FFFFFFFF00010000000000000001000000000000000100000001800000000000000000FFFFFFFF00000000000000000001000000000000000100000001801780000000000000FFFFFFFF00010000000000000001000000000000000100000001801D80000000000000FFFFFFFF00010000000000000001000000000000000100000001800000000000000000FFFFFFFF00000000000000000001000000000000000100000001801A80000000000000FFFFFFFF00010000000000000001000000000000000100000001801B80000000000000FFFFFFFF0001000000000000000100000000000000010000000180E57F000000000000FFFFFFFF00010000000000000001000000000000000100000001801C80000000000000FFFFFFFF00010000000000000001000000000000000100000001800000000000000000FFFFFFFF00000000000000000001000000000000000100000001800089000000000000FFFFFFFF00010000000000000001000000000000000100000001800000000000000000FFFFFFFF0000000000000000000100000000000000010000000180E48B000000000000FFFFFFFF0001000000000000000100000000000000010000000180F07F000000000000FFFFFFFF0001000000000000000100000000000000010000000180E888000000000000FFFFFFFF00010000000000000001000000000000000100000001803B01000000000000FFFFFFFF0001000000000000000100000000000000010000000180BB8A000000000000FFFFFFFF0001000000000000000100000000000000010000000180D88B000000000000FFFFFFFF0001000000000000000100000000000000010000000180D28B000000000000FFFFFFFF00010000000000000001000000000000000100000001809307000000000000FFFFFFFF0001000000000000000100000000000000010000000180658A000000000000FFFFFFFF0001000000000000000100000000000000010000000180C18A000000000000FFFFFFFF0001000000000000000100000000000000010000000180EE8B000000000000FFFFFFFF00010000000000000001000000000000000100000001800000000000000000FFFFFFFF00000000000000000001000000000000000100000001800189000000000000FFFFFFFF000100000000000000010000000000000001000000 + + + 898 + 1900FFFF01001100434D4643546F6F6C426172427574746F6ECC880000000000000000000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF000000000000000000000000000100000001000000018017800000000000000100000000000000000000000000000000010000000100000001801D800000000000000200000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF00000000000000000000000000010000000100000001801A800000000000000300000000000000000000000000000000010000000100000001801B80000000000000040000000000000000000000000000000001000000010000000180E57F0000000000000500000000000000000000000000000000010000000100000001801C800000000000000600000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF000000000000000000000000000100000001000000018000890000000000000700000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180E48B000000000000080000000000000000000000000000000001000000010000000180F07F000000000000090000000000000000000000000000000001000000010000000180E8880000000000000A00000000000000000000000000000000010000000100000001803B010000000000000B0000000000000000000000000000000001000000010000000180BB8A0000000000000C0000000000000000000000000000000001000000010000000180D88B0000000000000D0000000000000000000000000000000001000000010000000180D28B0000000000000E000000000000000000000000000000000100000001000000018093070000000000000F0000000000000000000000000000000001000000010000000180658A000000000000100000000000000000000000000000000001000000010000000180C18A000000000000110000000000000000000000000000000001000000010000000180EE8B0000000000001200000000000000000000000000000000010000000100000001800000000001000000FFFFFFFF0000000000000000000000000001000000010000000180018900000000000013000000000000000000000000000000000100000001000000 + + + + 0 + 1920 + 1080 + + + + + + 1 + 0 + + 100 + 0 + + ../Core/Src/main.c + 47 + 90 + 97 + 1 + + 0 + + + ..\..\Modbus\Src\modbus.c + 3 + 94 + 115 + 1 + + 0 + + + ..\..\Modbus\Src\modbus_data.c + 0 + 1 + 1 + 1 + + 0 + + + ../Core/Src/gpio.c + 0 + 1 + 1 + 1 + + 0 + + + ..\..\Modbus\Inc\modbus_config.h + 16 + 28 + 42 + 1 + + 0 + + + ..\..\Modbus\Inc\modbus_core.h + 0 + 149 + 177 + 1 + + 0 + + + + +
diff --git a/STM32F103_Example/MDK-ARM/Modbus_example.uvoptx b/STM32F103_Example/MDK-ARM/Modbus_example.uvoptx index 786a119..6c2043f 100644 --- a/STM32F103_Example/MDK-ARM/Modbus_example.uvoptx +++ b/STM32F103_Example/MDK-ARM/Modbus_example.uvoptx @@ -556,114 +556,6 @@ 5 23 - 1 - 0 - 0 - 0 - ..\..\Modbus\Src\__crc_algs.c - __crc_algs.c - 0 - 0 - - - 5 - 24 - 1 - 0 - 0 - 0 - ..\..\Modbus\Src\modbus.c - modbus.c - 0 - 0 - - - 5 - 25 - 1 - 0 - 0 - 0 - ..\..\Modbus\Src\modbus_coils.c - modbus_coils.c - 0 - 0 - - - 5 - 26 - 1 - 0 - 0 - 0 - ..\..\Modbus\Src\modbus_core.c - modbus_core.c - 0 - 0 - - - 5 - 27 - 1 - 0 - 0 - 0 - ..\..\Modbus\Src\modbus_data.c - modbus_data.c - 0 - 0 - - - 5 - 28 - 1 - 0 - 0 - 0 - ..\..\Modbus\Src\modbus_devid.c - modbus_devid.c - 0 - 0 - - - 5 - 29 - 1 - 0 - 0 - 0 - ..\..\Modbus\Src\modbus_holdregs.c - modbus_holdregs.c - 0 - 0 - - - 5 - 30 - 1 - 0 - 0 - 0 - ..\..\Modbus\Src\modbus_inputregs.c - modbus_inputregs.c - 0 - 0 - - - 5 - 31 - 1 - 0 - 0 - 0 - ..\..\Modbus\Src\rs_message.c - rs_message.c - 0 - 0 - - - 5 - 32 5 0 0 @@ -675,7 +567,19 @@ 5 - 33 + 24 + 1 + 0 + 0 + 0 + ..\..\Modbus\Src\modbus_data.c + modbus_data.c + 0 + 0 + + + 5 + 25 5 0 0 @@ -685,6 +589,138 @@ 0 0 + + 5 + 26 + 1 + 0 + 0 + 0 + ..\..\Modbus\Src\modbus.c + modbus.c + 0 + 0 + + + 5 + 27 + 1 + 0 + 0 + 0 + ..\..\Modbus\Src\modbus_master.c + modbus_master.c + 0 + 0 + + + 5 + 28 + 1 + 0 + 0 + 0 + ..\..\Modbus\Src\modbus_slave.c + modbus_slave.c + 0 + 0 + + + 5 + 29 + 1 + 0 + 0 + 0 + ..\..\Modbus\Src\modbus_coils.c + modbus_coils.c + 0 + 0 + + + 5 + 30 + 1 + 0 + 0 + 0 + ..\..\Modbus\Src\modbus_core.c + modbus_core.c + 0 + 0 + + + 5 + 31 + 1 + 0 + 0 + 0 + ..\..\Modbus\Src\modbus_holdregs.c + modbus_holdregs.c + 0 + 0 + + + 5 + 32 + 1 + 0 + 0 + 0 + ..\..\Modbus\Src\modbus_inputregs.c + modbus_inputregs.c + 0 + 0 + + + 5 + 33 + 1 + 0 + 0 + 0 + ..\..\Modbus\Src\modbus_devid.c + modbus_devid.c + 0 + 0 + + + 5 + 34 + 1 + 0 + 0 + 0 + ..\..\Modbus\Src\modbus_diag.c + modbus_diag.c + 0 + 0 + + + 5 + 35 + 1 + 0 + 0 + 0 + ..\..\Modbus\Src\rs_message.c + rs_message.c + 0 + 0 + + + 5 + 36 + 1 + 0 + 0 + 0 + ..\..\Modbus\Src\__crc_algs.c + __crc_algs.c + 0 + 0 + diff --git a/STM32F103_Example/MDK-ARM/Modbus_example.uvprojx b/STM32F103_Example/MDK-ARM/Modbus_example.uvprojx index debffbb..59d2a40 100644 --- a/STM32F103_Example/MDK-ARM/Modbus_example.uvprojx +++ b/STM32F103_Example/MDK-ARM/Modbus_example.uvprojx @@ -567,15 +567,35 @@ Modbus - __crc_algs.c + modbus_config.h + 5 + ..\..\Modbus\Inc\modbus_config.h + + + modbus_data.c 1 - ..\..\Modbus\Src\__crc_algs.c + ..\..\Modbus\Src\modbus_data.c + + + modbus_data.h + 5 + ..\..\Modbus\Inc\modbus_data.h modbus.c 1 ..\..\Modbus\Src\modbus.c + + modbus_master.c + 1 + ..\..\Modbus\Src\modbus_master.c + + + modbus_slave.c + 1 + ..\..\Modbus\Src\modbus_slave.c + modbus_coils.c 1 @@ -586,16 +606,6 @@ 1 ..\..\Modbus\Src\modbus_core.c - - modbus_data.c - 1 - ..\..\Modbus\Src\modbus_data.c - - - modbus_devid.c - 1 - ..\..\Modbus\Src\modbus_devid.c - modbus_holdregs.c 1 @@ -606,20 +616,25 @@ 1 ..\..\Modbus\Src\modbus_inputregs.c + + modbus_devid.c + 1 + ..\..\Modbus\Src\modbus_devid.c + + + modbus_diag.c + 1 + ..\..\Modbus\Src\modbus_diag.c + rs_message.c 1 ..\..\Modbus\Src\rs_message.c - modbus_config.h - 5 - ..\..\Modbus\Inc\modbus_config.h - - - modbus_data.h - 5 - ..\..\Modbus\Inc\modbus_data.h + __crc_algs.c + 1 + ..\..\Modbus\Src\__crc_algs.c