/** ******************************************************************************* * @file modbus_core.h * @brief Ядро Modbus протокола - определения и структуры ******************************************************************************* @addtogroup MODBUS_INTERNAL Modbus Internal Tools @ingroup MODBUS @brief Внутренние штуки библиотеки @{ ******************************************************************************* * @details Базовые определения для реализации Modbus RTU устройства: - Структуры сообщений Modbus Коды функций и исключений Константы размеров полей Вспомогательные макросы @section msg Структура сообщения: [ADDR][FUNC][DATA...][CRC] - Адрес: 1 байт - Функция: 1 байт - Данные: переменной длины - CRC: 2 байта ******************************************************************************/ #ifndef __MODBUS_CORE_H_ #define __MODBUS_CORE_H_ #include "modbus_config.h" #include "modbus_data.h" #include "__crc_algs.h" /** * @addtogroup MODBUS_MESSAGE_DEFINES Modbus Message Tools * @ingroup MODBUS * @brief Определения протокола модбас * @{ */ ///////////////////////////////////////////////////////////////////// ////////////////////---MODBUS MESSAGE DEFINES---///////////////////// //-------------DEFINES FOR STRUCTURE---------------- /* defines for structure of modbus message */ #define MbTransactionID_size 2 ///< size of (Transaction ID) #define MbProtocolID_size 2 ///< size of (Protocol ID) #define MbPDULength_size 2 ///< size of (PDU Length) #define MbDeviceAddr_size 1 ///< size of (Slave Addr) #define MbFuncCode_size 1 ///< size of (Function Code) #define MbAddr_size 2 ///< size of (Address) #define MbQnt_size 2 ///< size of (Quantity) #define MbByteCnt_size 1 ///< size of (Byte Count) #define MbData_size 125 ///< maximum number of data: DWORD (NOT MESSAGE SIZE) #define MbCRC_size 2 ///< size of (MbCRC) in bytes #ifndef MODBUS_PROTOCOL_TCP /** @brief Size of whole RTU message */ #define RS_INFO_SIZE_MAX (MbDeviceAddr_size+MbFuncCode_size+MbAddr_size+MbQnt_size+MbByteCnt_size) #else /** @brief Size of whole TCP message */ #define RS_INFO_SIZE_MAX (MbTransactionID_size+MbProtocolID_size+MbPDULength_size+MbDeviceAddr_size+MbFuncCode_size+MbAddr_size+MbQnt_size) #endif /** @brief Size of first part of message that will be received first receive info part of message, than defines size of rest message*/ #define RS_RX_FIRST_PART_SIZE RS_INFO_SIZE_MAX /** @brief Size of buffer: max size of whole message */ #define RS_MSG_SIZE_MAX (RS_INFO_SIZE_MAX + MbData_size*2 + MbCRC_size) // max possible size of message /** * @brief Enum for modbus exception codes * @details Prefix ET for Error Type */ typedef enum //MB_ExceptionTypeDef { // reading ET_NO_ERRORS = 0x00, ///< no errors ET_ILLEGAL_FUNCTION = 0x01, ///< Принятый код функции не может быть обработан ET_ILLEGAL_DATA_ADDRESS = 0x02, ///< Адрес данных, указанный в запросе, недоступен ET_ILLEGAL_DATA_VALUE = 0x03, ///< Значение, содержащееся в поле данных запроса, является недопустимой величиной ET_SLAVE_DEVICE_FAILURE = 0x04, ///< Невосстанавливаемая ошибка имела место, пока ведомое устройство пыталось выполнить затребованное действие // ET_ACKNOWLEDGE = 0x05, ///< idk // ET_SLAVE_DEVICE_BUSY = 0x06, ///< idk // ET_MEMORY_PARITY_ERROR = 0x08, ///< idk }MB_ExceptionTypeDef; #define FC_ERR_VALUES_START 0x80U ///< from this value starts error func codes /** * @brief Enum for modbus func codes * @details Prefix FC for Function Code */ typedef enum //MB_FunctonTypeDef { /* COMMANDS */ // reading FC_R_COILS = 0x01, ///< Чтение битовых ячеек FC_R_DISC_IN = 0x02, ///< Чтение дискретных входов #ifndef MODBUS_SWITCH_COMMAND_R_IN_REGS_AND_R_HOLD_REGS FC_R_HOLD_REGS = 0x03, ///< Чтение входных регистров FC_R_IN_REGS = 0x04, ///< Чтение регистров хранения #else FC_R_HOLD_REGS = 0x04, ///< Чтение входных регистров FC_R_IN_REGS = 0x03, ///< Чтение регистров хранения #endif // writting FC_W_COIL = 0x05, ///< Запись битовой ячейки FC_W_HOLD_REG = 0x06, ///< Запись одиночного регистра FC_W_COILS = 0x0F, ///< Запись нескольких битовых ячеек FC_W_HOLD_REGS = 0x10, ///< Запись нескольких регистров FC_R_DIAGNOSTICS = 0x08, ///< Чтение диагностической информации устройства FC_R_DEVICE_ID = 0x2B, ///< Чтение информации об устройстве /* ERRORS */ // error reading FC_ERR_R_COILS = FC_R_COILS + FC_ERR_VALUES_START, ///< Ошибка чтения битовых ячеек FC_ERR_R_DISC_IN = FC_R_DISC_IN + FC_ERR_VALUES_START, ///< Ошибка чтения дискретных входов FC_ERR_R_IN_REGS = FC_R_IN_REGS + FC_ERR_VALUES_START, ///< Ошибка чтения регистров хранения FC_ERR_R_HOLD_REGS = FC_R_HOLD_REGS + FC_ERR_VALUES_START, ///< Ошибка чтения входных регистров // error writting FC_ERR_W_COIL = FC_W_COIL + FC_ERR_VALUES_START, ///< Ошибка записи битовой ячейки FC_ERR_W_HOLD_REG = FC_W_HOLD_REG + FC_ERR_VALUES_START, ///< Ошибка записи одиночного регистра FC_ERR_W_COILS = FC_W_COILS + FC_ERR_VALUES_START, ///< Ошибка записи нескольких битовых ячеек FC_ERR_W_HOLD_REGS = FC_W_HOLD_REGS + FC_ERR_VALUES_START, ///< Ошибка записи нескольких регистров FC_ERR_R_DIAGNOSTIC = FC_R_DIAGNOSTICS + FC_ERR_VALUES_START, ///< Ошибка чтения диагностической информации устройства FC_ERR_R_DEVICE_INFO = FC_R_DEVICE_ID + FC_ERR_VALUES_START, ///< Ошибка чтения информации об устройстве }MB_FunctonTypeDef; /** * @brief Enum for MEI func codes */ typedef enum //MB_FunctonTypeDef { MEI_DEVICE_IDENTIFICATIONS = 0x0E, }MB_MEITypeDef; /** * @brief Enum for Read Device Id codes * @details Prefix RID for Read ID */ typedef enum //MB_FunctonTypeDef { RID_BASIC_IDENTIFICATIONS = 0x01, /*!< @brief Basic Device Identifications. @details All objects of this category are mandatory: VendorName, Product code, and revision number */ RID_REGULAR_IDENTIFICATIONS = 0x02, /*!< @brief Regular Device Identifications. @details The device provides additional and optional identifications and description data objects */ RID_EXTENDED_IDENTIFICATIONS = 0x03, /*!< @brief Extended Device Identifications. @details The device provides additional and optional identifications and description private data about the physical device itself. All of these data are device dependent. */ RID_SPEDIFIC_IDENTIFICATIONS = 0x04, /*!< @brief Specific Device Identifications. @details The device provides one specific identifications object. */ }MB_ReadDevId; /** @brief Structure for device identifications message type */ typedef struct { MB_MEITypeDef MEI_Type; ///< MEI Type assigned number for Device Identifications Interface MB_ReadDevId ReadDevId; uint8_t Conformity; ///< Identification conformity level of the device and type of supported access @ref MODBUS_DEVICE_CONFORMITY uint8_t MoreFollows; uint8_t NextObjId; uint8_t NumbOfObj; }MB_DevIdMsgTypeDef; /** @brief Structure for modbus messsage */ typedef struct // RS_MsgTypeDef { #ifdef MODBUS_PROTOCOL_TCP uint16_t TransactionID; ///< Modbus TCP: ID Transaction uint16_t ProtocolID; ///< Modbus TCP: ID Protocol uint16_t PDULength; ///< Modbus TCP: PDU Length #endif uint8_t DeviceAddr; ///< Modbus Slave Address MB_FunctonTypeDef FuncCode; ///< Modbus Function Code MB_DevIdMsgTypeDef DevId; ///< Read Device Identifications Header struct 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 MbData[MbData_size]; ///< Modbus Data MB_ExceptionTypeDef Except_Code; ///< Exception Code for the command uint16_t MbCRC; ///< Modbus CRC }RS_MsgTypeDef; //-------------------------------------------------- extern RS_MsgTypeDef MODBUS_MSG; ////////////////////---MODBUS MESSAGE DEFINES---///////////////////// ///////////////////////////////////////////////////////////////////// ////////////////////---MODBUS FUNCTION DEFINES---//////////////////// /** * @brief Macros to set pointer to 16-bit array * @param _arr_ - массив регистров (16-бит). */ #define MB_Set_Arr16_Ptr(_arr_) ((uint16_t*)(&(_arr_))) /** * @brief Macros to set pointer to register * @param _parr_ - массив регистров. * @param _addr_ - Номер регистра (его индекс) от начала массива _arr_. */ #define MB_Set_Register_Ptr(_parr_, _addr_) ((uint16_t *)(_parr_)+(_addr_)) /** * @brief Макрос для установки указателя на регистр, содержащий запрашиваемый коил * @param _parr_ - массив коилов. * @param _coil_ - Номер коила от начала массива _arr_. * @note Используется вместе с @ref MB_Set_Coil_Mask @code Пояснение выражений - (_coil_/16) - индекс регистра, в котором содержится коил по адресу _coil_ Визуальный пример: 30 коил будет в 30/16 = 1 регистре (индексация с 0) xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx |register[0]----| |register[1]----| |skip this------| |get this-------| |shift to 14 bit| @endcode */ #define MB_Set_Coil_Reg_Ptr(_parr_, _coil_) ((uint16_t *)(_parr_)+((_coil_)/16)) /** * @brief Макрос для установки маски, чтобы выделить запрашиваемый коил из регистра * @param _coil_ - Номер коила от начала массива _arr_. * @note Используется вместе с @ref MB_Set_Coil_Reg_Ptr @code Пояснение выражений - (16*(_coil_/16) - сколько коилов нужно пропустить. прим. (16*30/16) - первые 16 коилов находятся вне регистра - _coil_-(16*(_coil_/16)) - сдвинуть бит на место запрашиваемого коила в регистре Визуальный пример: 30 коил будет регистре[1], на 14 бите: register = 30/16 = 1 bit = 30 - (16*30/16) = 30 - 16 = 14 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxCx |register[0]----| |register[1]----| |skip this------| |get this-------| |shift to 14 bit| @endcode */ #define MB_Set_Coil_Mask(_coil_) (1 << ( _coil_ - (16*((_coil_)/16)) )) /** GENERAL_MODBUS_STUFF * @} */ //------------------OTHER DEFINES------------------- #define RegisterType_Holding 0 #define RegisterType_Input 1 #define RegisterType_Discrete 2 // create hadnles and settings for uart, tim, rs with _modbus_ name //-------------------------------------------------- #ifndef Divide_Up /** * @brief Calc dividing including remainder * @param _val_ - делимое. * @param _div_ - делитель. * @details Если результат деления без остатка: он возвращается как есть Если с остатком - округляется вверх */ //#define Divide_Up(_val_, _div_) (((_val_)%(_div_))? (_val_)/(_div_)+1 : (_val_)/_div_) /* через тернарный оператор */ #define Divide_Up(_val_, _div_) ((_val_ - 1) / _div_) + 1 /* через мат выражение */ #endif #ifndef ByteSwap16 /** * @brief Swap between Little Endian and Big Endian * @param v - Переменная для свапа. * @return v (new) - Свапнутая переменная. * @details Переключения между двумя типами хранения слова: HI-LO байты и LO-HI байты. */ #define ByteSwap16(v) (((v&0xFF00) >> (8)) | ((v&0x00FF) << (8))) #endif ////////////////////---MODBUS MESSAGE DEFINES---///////////////////// ///////////////////////////////////////////////////////////////////// /////////////////////////---FUNCTIONS---///////////////////////////// /** * @addtogroup MODBUS_CMD_PROCESS_FUNCTIONS * @{ */ /* Реализация этих функций лежит в modbus_data.c */ /* Check is address valid for certain array */ MB_ExceptionTypeDef MB_Check_Address_For_Arr(uint16_t Addr, uint16_t Qnt, uint16_t R_ARR_ADDR, uint16_t R_ARR_NUMB); /* Define Address Origin for Input/Holding Registers */ MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, uint16_t Qnt, uint8_t RegisterType, uint8_t WriteFlag); /* Define Address Origin for coils */ MB_ExceptionTypeDef MB_DefineCoilsAddress(uint16_t **pCoils, uint16_t Addr, uint16_t Qnt, uint16_t *start_shift, uint8_t WriteFlag); /** MODBUS_CMD_PROCESS_FUNCTIONS * @} */ /////////////////////////---FUNCTIONS---///////////////////////////// #include "__modbus_compat.h" #endif //__MODBUS_CORE_H_ /** MODBUS_INTERNAL * @} */