/** ************************************************************************** * @file modbus.h * @brief Заголовочный файл модуля MODBUS. * @details Данный файл необходимо подключить в rs_message.h. После подключать * rs_message.h к основному проекту. * * @defgroup MODBUS * @brief Modbus stuff * *************************************************************************/ #ifndef __MODBUS_H_ #define __MODBUS_H_ #include "mylibs_include.h" #include "modbus_data.h" //#include "settings.h" // for modbus settings /** * @addtogroup MODBUS_SETTINGS * @ingroup MODBUS * @brief Some defines for modbus @{ */ ///////////////////////////////////////////////////////////////////// //////////////////////////---SETTINGS---///////////////////////////// // USER SETTINGS FOR MODBUS IN interface_config.h //////////////////////////---SETTINGS---///////////////////////////// ///////////////////////////////////////////////////////////////////// /////////////////////---USER MESSAGE DEFINES---////////////////////// //-------------DEFINES FOR STRUCTURE---------------- /* defines for structure of modbus message */ #define MbAddr_SIZE 1 ///< size of (MbAddr) #define Func_Code_SIZE 1 ///< size of (Func_Code) #define Addr_SIZE 2 ///< size of (Addr) #define Qnt_SIZE 2 ///< size of (Qnt) #define ByteCnt_SIZE 1 ///< size of (ByteCnt) #define DATA_SIZE 125 ///< maximum number of data: DWORD (NOT MESSAGE SIZE) #define CRC_SIZE 2 ///< size of (MB_CRC) in bytes /** @brief Size of whole message */ #define INFO_SIZE_MAX (MbAddr_SIZE+Func_Code_SIZE+Addr_SIZE+Qnt_SIZE+ByteCnt_SIZE) /** @brief Size of first part of message that will be received first receive info part of message, than defines size of rest message*/ #define RX_FIRST_PART_SIZE INFO_SIZE_MAX /** @brief Size of buffer: max size of whole message */ #define MSG_SIZE_MAX (INFO_SIZE_MAX + DATA_SIZE*2 + CRC_SIZE) // max possible size of message /** @brief Structure for modbus exception codes */ typedef enum //MB_ExceptionTypeDef { // reading NO_ERRORS = 0x00, ///< no errors ILLEGAL_FUNCTION = 0x01, ///< Принятый код функции не может быть обработан ILLEGAL_DATA_ADDRESS = 0x02, ///< Адрес данных, указанный в запросе, недоступен ILLEGAL_DATA_VALUE = 0x03, ///< Значение, содержащееся в поле данных запроса, является недопустимой величиной SLAVE_DEVICE_FAILURE = 0x04, ///< Невосстанавливаемая ошибка имела место, пока ведомое устройство пыталось выполнить затребованное действие // ACKNOWLEDGE = 0x05, ///< idk // SLAVE_DEVICE_BUSY = 0x06, ///< idk // MEMORY_PARITY_ERROR = 0x08, ///< idk }MB_ExceptionTypeDef; #define ERR_VALUES_START 0x80U ///< from this value starts error func codes /** @brief Structure for modbus func codes */ typedef enum //MB_FunctonTypeDef { /* COMMANDS */ // reading MB_R_COILS = 0x01, ///< Чтение битовых ячеек MB_R_DISC_IN = 0x02, ///< Чтение дискретных входов #ifndef MODBUS_SWITCH_COMMAND_R_IN_REGS_AND_R_HOLD_REGS MB_R_HOLD_REGS = 0x03, ///< Чтение входных регистров MB_R_IN_REGS = 0x04, ///< Чтение регистров хранения #else MB_R_HOLD_REGS = 0x04, ///< Чтение входных регистров MB_R_IN_REGS = 0x03, ///< Чтение регистров хранения #endif // writting MB_W_COIL = 0x05, ///< Запись битовой ячейки MB_W_HOLD_REG = 0x06, ///< Запись одиночного регистра MB_W_COILS = 0x0F, ///< Запись нескольких битовых ячеек MB_W_HOLD_REGS = 0x10, ///< Запись нескольких регистров /* ERRORS */ // error reading MB_ERR_R_COILS = MB_R_COILS + ERR_VALUES_START, ///< Ошибка чтения битовых ячеек MB_ERR_R_DISC_IN = MB_R_DISC_IN + ERR_VALUES_START, ///< Ошибка чтения дискретных входов MB_ERR_R_IN_REGS = MB_R_IN_REGS + ERR_VALUES_START, ///< Ошибка чтения регистров хранения MB_ERR_R_HOLD_REGS = MB_R_HOLD_REGS + ERR_VALUES_START, ///< Ошибка чтения входных регистров // error writting MB_ERR_W_COIL = MB_W_COIL + ERR_VALUES_START, ///< Ошибка записи битовой ячейки MB_ERR_W_HOLD_REG = MB_W_HOLD_REG + ERR_VALUES_START, ///< Ошибка записи одиночного регистра MB_ERR_W_COILS = MB_W_COILS + ERR_VALUES_START, ///< Ошибка записи нескольких битовых ячеек MB_ERR_W_HOLD_REGS = MB_W_HOLD_REGS + ERR_VALUES_START, ///< Ошибка записи нескольких регистров }MB_FunctonTypeDef; /** @brief Structure for modbus messsage */ typedef struct // RS_MsgTypeDef { uint8_t MbAddr; ///< Modbus Slave Address MB_FunctonTypeDef Func_Code; ///< Modbus Function Code uint16_t Addr; ///< Modbus Address of data uint16_t Qnt; ///< Quantity of modbus data uint8_t ByteCnt; ///< Quantity of bytes of data in message to transmit/receive uint16_t DATA[DATA_SIZE]; ///< Modbus Data MB_ExceptionTypeDef Except_Code; ///< Exception Code for the command uint16_t MB_CRC; ///< Modbus CRC }RS_MsgTypeDef; //-------------------------------------------------- extern RS_MsgTypeDef MODBUS_MSG; /////////////////////---MODBUS USER SETTINGS---////////////////////// /** MODBUS_SETTINGS * @} */ ///////////////////////////////////////////////////////////////////// ////////////////////---MODBUS MESSAGE DEFINES---///////////////////// /** * @addtogroup MODBUS_MESSAGE_DEFINES * @ingroup MODBUS * @brief Some defines for modbus @{ */ /** @brief Structure for coils operation */ typedef enum { SET_COIL, RESET_COIL, TOOGLE_COIL, }MB_CoilsOpTypeDef; //-------------------------------------------------- /** * @brief Macros to set pointer to 16-bit array * @param _arr_ - массив регистров (16-бит). */ #define MB_Set_Arr16_Ptr(_arr_) ((uint16_t*)(&(_arr_))) /** * @brief Macros to set pointer to register * @param _parr_ - массив регистров. * @param _addr_ - Номер регистра (его индекс) от начала массива _arr_. */ #define MB_Set_Register_Ptr(_parr_, _addr_) ((uint16_t *)(_parr_)+(_addr_)) /** * @brief Macros to set pointer to a certain register that contains certain coil * @param _parr_ - массив коилов. * @param _coil_ - Номер коила от начала массива _arr_. * @note Используется вместе с @ref MB_Set_Coil_Mask @verbatim Пояснение выражений (_coil_/16) - get index (address shift) of register that contain certain coil Visual explanation: 30th coil in coils registers array xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx |register[0]----| |register[1]----| |skip this------| |get this-------| |shift to 14 bit| @endverbatim */ #define MB_Set_Coil_Reg_Ptr(_parr_, _coil_) ((uint16_t *)(_parr_)+((_coil_)/16)) /** * @brief Macros to set mask to a certain bit in coils register * @param _coil_ - Номер коила от начала массива _arr_. * @note Используется вместе с @ref MB_Set_Coil_Reg_Ptr @verbatim Пояснение выражений (16*(_coil_/16) - how many coils we need to skip. e.g. (16*30/16) - skip 16 coils from first register _coil_-(16*(_coil_/16)) - shift to certain coil in certain register e.g. Coil(30) gets in register[1] (30/16 = 1) coil №14 (30 - (16*30/16) = 30 - 16 = 14) Visual explanation: 30th coil in coils registers array xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx |register[0]----| |register[1]----| |skip this------| |get this-------| |shift to 14 bit| @endverbatim */ #define MB_Set_Coil_Mask(_coil_) (1 << ( _coil_ - (16*((_coil_)/16)) )) /** * @brief Read Coil at its local address. * @param _parr_ - массив коилов. * @param _coil_ - Номер коила от начала массива _arr_. * @return uint16_t - Возвращает запрошенный коил на 0м бите. * * @details Позволяет обратиться к коилу по адресу относительно _arr_. */ #define MB_Read_Coil_Local(_parr_, _coil_) (( *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) & MB_Set_Coil_Mask(_coil_) ) >> (_coil_)) /** * @brief Set Coil at its local address. * @param _parr_ - указатель на массив коилов. * @param _coil_ - Номер коила от начала массива _arr_. * * @details Позволяет обратиться к коилу по адресу относительно _arr_. */ #define MB_Set_Coil_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) |= MB_Set_Coil_Mask(_coil_) /** * @brief Reset Coil at its local address. * @param _parr_ - указатель на массив коилов. * @param _coil_ - Номер коила от начала массива _arr_. * * @details Позволяет обратиться к коилу по адресу относительно _arr_. */ #define MB_Reset_Coil_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) &= ~(MB_Set_Coil_Mask(_coil_)) /** * @brief Set Coil at its local address. * @param _parr_ - указатель на массив коилов. * @param _coil_ - Номер коила от начала массива _arr_. * * @details Позволяет обратиться к коилу по адресу относительно _arr_. */ #define MB_Toogle_Coil_Local(_parr_, _coil_) *MB_Set_Coil_Reg_Ptr(_parr_, _coil_) ^= MB_Set_Coil_Mask(_coil_) //-------------------------------------------------- //------------------OTHER DEFINES------------------- #define RegisterType_Holding 0 #define RegisterType_Input 1 #define RegisterType_Discrete 2 // create hadnles and settings for uart, tim, rs with _modbus_ name #define CONCAT(a,b) a##b #define Create_MODBUS_Handles(_modbus_) \ UART_SettingsTypeDef CONCAT(_modbus_, _suart); \ UART_HandleTypeDef CONCAT(_modbus_, _huart); \ TIM_SettingsTypeDef CONCAT(_modbus_, _stim); \ TIM_HandleTypeDef CONCAT(_modbus_, _htim); \ RS_HandleTypeDef CONCAT(h, _modbus_) //-------------------------------------------------- /** GENERAL_MODBUS_STUFF * @} */ ////////////////////---MODBUS MESSAGE DEFINES---///////////////////// ///////////////////////////////////////////////////////////////////// /////////////////////////---FUNCTIONS---///////////////////////////// /** * @addtogroup MODBUS_FUNCTIONS * @ingroup MODBUS * @brief Function for controling modbus communication */ //----------------FUNCTIONS FOR USER---------------- /** * @addtogroup MODBUS_DATA_ACCESS_FUNCTIONS * @ingroup MODBUS_FUNCTIONS * @brief Function for user use @{ */ /* First set up of MODBUS */ void MODBUS_FirstInit(void); /* Set or Reset Coil at its global address */ MB_ExceptionTypeDef MB_Write_Coil_Global(uint16_t Addr, MB_CoilsOpTypeDef WriteVal); /* Read Coil at its global address */ uint16_t MB_Read_Coil_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception); /** MODBUS_DATA_ACCESS_FUNCTIONS * @} */ //---------PROCESS MODBUS COMMAND FUNCTIONS--------- /** * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS * @ingroup MODBUS_FUNCTIONS * @brief Function process commands @{ */ /* Check is address valid for certain array */ MB_ExceptionTypeDef MB_Check_Address_For_Arr(uint16_t Addr, uint16_t Qnt, uint16_t R_ARR_ADDR, uint16_t R_ARR_NUMB); /* Define Address Origin for Input/Holding Registers */ MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, uint16_t Qnt, uint8_t RegisterType); /* Define Address Origin for coils */ MB_ExceptionTypeDef MB_DefineCoilsAddress(uint16_t **pCoils, uint16_t Addr, uint16_t Qnt, uint16_t *start_shift, uint8_t WriteFlag); /* Proccess command Read Coils (01 - 0x01) */ uint8_t MB_Read_Coils(RS_MsgTypeDef *modbus_msg); /* Proccess command Read Holding Registers (03 - 0x03) */ uint8_t MB_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg); /* Proccess command Read Input Registers (04 - 0x04) */ uint8_t MB_Read_Input_Regs(RS_MsgTypeDef *modbus_msg); /* Proccess command Write Single Coils (05 - 0x05) */ uint8_t MB_Write_Single_Coil(RS_MsgTypeDef *modbus_msg); /* Proccess command Write Multiple Coils (15 - 0x0F) */ uint8_t MB_Write_Miltuple_Coils(RS_MsgTypeDef *modbus_msg); /* Proccess command Write Multiple Register (16 - 0x10) */ uint8_t MB_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg); /** MODBUS_DATA_ACCESS_FUNCTIONS * @} */ /////////////////////////---FUNCTIONS---///////////////////////////// ///////////////////////////////////////////////////////////////////// /////////////////////////---CALC DEFINES---////////////////////////// // TRACES DEFINES #ifndef Trace_MB_UART_Enter #define Trace_MB_UART_Enter() #endif //Trace_MB_UART_Enter #ifndef Trace_MB_UART_Exit #define Trace_MB_UART_Exit() #endif //Trace_MB_UART_Exit #ifndef Trace_MB_TIM_Enter #define Trace_MB_TIM_Enter() #endif //Trace_MB_TIM_Enter #ifndef Trace_MB_TIM_Exit #define Trace_MB_TIM_Exit() #endif //Trace_MB_TIM_Exit #endif //__MODBUS_H_