Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: Nucleo_modbus_protocol_test
ModbusSlaveRTU.h@0:81fee41d95f1, 2015-01-19 (annotated)
- Committer:
- gabrielrivas
- Date:
- Mon Jan 19 03:29:36 2015 +0000
- Revision:
- 0:81fee41d95f1
- Child:
- 1:5efaa10b9a3f
First version of ModbusSlaveRTU for C++.
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| gabrielrivas | 0:81fee41d95f1 | 1 | #ifndef _MODBUS_SLAVE_RTU_H_ |
| gabrielrivas | 0:81fee41d95f1 | 2 | #define _MODBUS_SLAVE_RTU_H_ |
| gabrielrivas | 0:81fee41d95f1 | 3 | |
| gabrielrivas | 0:81fee41d95f1 | 4 | #include "mbed.h" |
| gabrielrivas | 0:81fee41d95f1 | 5 | #include "rtos.h" |
| gabrielrivas | 0:81fee41d95f1 | 6 | #include "MessageQueue.h" |
| gabrielrivas | 0:81fee41d95f1 | 7 | |
| gabrielrivas | 0:81fee41d95f1 | 8 | #define MODBUS_MAX_LEN (256) |
| gabrielrivas | 0:81fee41d95f1 | 9 | |
| gabrielrivas | 0:81fee41d95f1 | 10 | struct ThreadSafeArray_t { |
| gabrielrivas | 0:81fee41d95f1 | 11 | Mutex mutex; |
| gabrielrivas | 0:81fee41d95f1 | 12 | uint8_t *data; |
| gabrielrivas | 0:81fee41d95f1 | 13 | uint32_t length; |
| gabrielrivas | 0:81fee41d95f1 | 14 | }; |
| gabrielrivas | 0:81fee41d95f1 | 15 | |
| gabrielrivas | 0:81fee41d95f1 | 16 | class ModbusSlaveRTU |
| gabrielrivas | 0:81fee41d95f1 | 17 | { |
| gabrielrivas | 0:81fee41d95f1 | 18 | public: |
| gabrielrivas | 0:81fee41d95f1 | 19 | /*! Modbus response message bytes indexes. */ |
| gabrielrivas | 0:81fee41d95f1 | 20 | enum MbResponseByteIndex_t { |
| gabrielrivas | 0:81fee41d95f1 | 21 | ADDRESS = 0, |
| gabrielrivas | 0:81fee41d95f1 | 22 | FUNCTION = 1, |
| gabrielrivas | 0:81fee41d95f1 | 23 | BYTE_COUNT = 2, |
| gabrielrivas | 0:81fee41d95f1 | 24 | DATA_START = 3 |
| gabrielrivas | 0:81fee41d95f1 | 25 | }; |
| gabrielrivas | 0:81fee41d95f1 | 26 | |
| gabrielrivas | 0:81fee41d95f1 | 27 | /*! Modbus errors reported during message processing. */ |
| gabrielrivas | 0:81fee41d95f1 | 28 | enum MbReceivedMessageErrors_t { |
| gabrielrivas | 0:81fee41d95f1 | 29 | ADDRESS_ERROR = 0x10, |
| gabrielrivas | 0:81fee41d95f1 | 30 | CRC_ERROR = 0x11, |
| gabrielrivas | 0:81fee41d95f1 | 31 | OFFSET_ERROR = 0x12, |
| gabrielrivas | 0:81fee41d95f1 | 32 | BYTE_COUNT_ERROR = 0x13 |
| gabrielrivas | 0:81fee41d95f1 | 33 | }; |
| gabrielrivas | 0:81fee41d95f1 | 34 | |
| gabrielrivas | 0:81fee41d95f1 | 35 | enum MbStatusTypes_t { |
| gabrielrivas | 0:81fee41d95f1 | 36 | MESSAGE_LISTENING = 0x20, |
| gabrielrivas | 0:81fee41d95f1 | 37 | MESSAGE_PROCESSING = 0x21, |
| gabrielrivas | 0:81fee41d95f1 | 38 | MESSAGE_SENDING = 0x23 |
| gabrielrivas | 0:81fee41d95f1 | 39 | }; |
| gabrielrivas | 0:81fee41d95f1 | 40 | |
| gabrielrivas | 0:81fee41d95f1 | 41 | enum MbSlaveRTUStates_t { |
| gabrielrivas | 0:81fee41d95f1 | 42 | WAIT_REQUEST_MESSAGE = 0x00, |
| gabrielrivas | 0:81fee41d95f1 | 43 | GET_RECEIVED_BYTES = 0x01, |
| gabrielrivas | 0:81fee41d95f1 | 44 | BUILD_RESPONSE_MESSAGE = 0x02, |
| gabrielrivas | 0:81fee41d95f1 | 45 | TRANSMIT_RESPONSE_MESSAGE = 0x03 |
| gabrielrivas | 0:81fee41d95f1 | 46 | }; |
| gabrielrivas | 0:81fee41d95f1 | 47 | |
| gabrielrivas | 0:81fee41d95f1 | 48 | /*! Modbus function codes. */ |
| gabrielrivas | 0:81fee41d95f1 | 49 | enum MbFunctionCodes_t { |
| gabrielrivas | 0:81fee41d95f1 | 50 | READ_COIL_STATUS = 0x01, /**< Function to read a single coil status.*/ |
| gabrielrivas | 0:81fee41d95f1 | 51 | READ_INPUT_STATUS = 0x02, /**< Function to read input register.*/ |
| gabrielrivas | 0:81fee41d95f1 | 52 | READ_HOLDING_REGISTERS = 0x03, /**< Function to read one or more internal holding resgisters.*/ |
| gabrielrivas | 0:81fee41d95f1 | 53 | READ_INPUT_REGISTERS = 0x04, /**< Function to read one or more input resgisters.*/ |
| gabrielrivas | 0:81fee41d95f1 | 54 | FORCE_SINGLE_COIL = 0x05, /**< Function to write a value into a single discrete output.*/ |
| gabrielrivas | 0:81fee41d95f1 | 55 | PRESET_SINGLE_REGISTER = 0x06, /**< Function to write a value into a single holding register.*/ |
| gabrielrivas | 0:81fee41d95f1 | 56 | READ_EXCEPTION_STATUS = 0x07, /**< Function to request the value of the status byte.*/ |
| gabrielrivas | 0:81fee41d95f1 | 57 | LOOPBACK_TEST = 0x08, /**< Function to test the communications interface. Returns the same message.*/ |
| gabrielrivas | 0:81fee41d95f1 | 58 | FORCE_MULTIPLE_COILS = 0x0F /**< Function to set more than one coil to a given value*/ |
| gabrielrivas | 0:81fee41d95f1 | 59 | }; |
| gabrielrivas | 0:81fee41d95f1 | 60 | |
| gabrielrivas | 0:81fee41d95f1 | 61 | /*! Modbus frame structure elements. */ |
| gabrielrivas | 0:81fee41d95f1 | 62 | struct MbSlaveRTUFrame_t { |
| gabrielrivas | 0:81fee41d95f1 | 63 | uint8_t mAddress; /**< Slave device address.*/ |
| gabrielrivas | 0:81fee41d95f1 | 64 | MbFunctionCodes_t mFunction; /**< Requested function of type MbFunctionCodes_t.*/ |
| gabrielrivas | 0:81fee41d95f1 | 65 | uint16_t mOffset; /**< Offset in bytes from the starting address.*/ |
| gabrielrivas | 0:81fee41d95f1 | 66 | uint16_t mByteCount; |
| gabrielrivas | 0:81fee41d95f1 | 67 | uint8_t mCRCH; |
| gabrielrivas | 0:81fee41d95f1 | 68 | uint8_t mCRCL; |
| gabrielrivas | 0:81fee41d95f1 | 69 | uint16_t mSize; |
| gabrielrivas | 0:81fee41d95f1 | 70 | }; |
| gabrielrivas | 0:81fee41d95f1 | 71 | |
| gabrielrivas | 0:81fee41d95f1 | 72 | struct MemoryMap_t { |
| gabrielrivas | 0:81fee41d95f1 | 73 | ThreadSafeArray_t *coilRegisters; |
| gabrielrivas | 0:81fee41d95f1 | 74 | ThreadSafeArray_t *holdingRegisters; |
| gabrielrivas | 0:81fee41d95f1 | 75 | ThreadSafeArray_t *inputRegisters; |
| gabrielrivas | 0:81fee41d95f1 | 76 | }; |
| gabrielrivas | 0:81fee41d95f1 | 77 | |
| gabrielrivas | 0:81fee41d95f1 | 78 | typedef struct MbSlaveRTUControl { |
| gabrielrivas | 0:81fee41d95f1 | 79 | uint8_t MbAddress; |
| gabrielrivas | 0:81fee41d95f1 | 80 | uint8_t rxByte; |
| gabrielrivas | 0:81fee41d95f1 | 81 | uint32_t receiveIndex; |
| gabrielrivas | 0:81fee41d95f1 | 82 | MbStatusTypes_t status; |
| gabrielrivas | 0:81fee41d95f1 | 83 | } MbSlaveRTUControl_t; |
| gabrielrivas | 0:81fee41d95f1 | 84 | |
| gabrielrivas | 0:81fee41d95f1 | 85 | |
| gabrielrivas | 0:81fee41d95f1 | 86 | public: |
| gabrielrivas | 0:81fee41d95f1 | 87 | /** |
| gabrielrivas | 0:81fee41d95f1 | 88 | * @brief Initialization function for the Modbus RTU Slave. |
| gabrielrivas | 0:81fee41d95f1 | 89 | * @param id. |
| gabrielrivas | 0:81fee41d95f1 | 90 | * @param *coilRegisters Pointer to the memory space reserved for the coil registers. |
| gabrielrivas | 0:81fee41d95f1 | 91 | * @param *inputRegisters Pointer to the memory space reserved for the input registers. |
| gabrielrivas | 0:81fee41d95f1 | 92 | * @param *inputRegisters Pointer to the memory space reserved for the holding registers. |
| gabrielrivas | 0:81fee41d95f1 | 93 | * @return void |
| gabrielrivas | 0:81fee41d95f1 | 94 | */ |
| gabrielrivas | 0:81fee41d95f1 | 95 | ModbusSlaveRTU( uint8_t id, |
| gabrielrivas | 0:81fee41d95f1 | 96 | MessageQueue<uint8_t>* txQueue, |
| gabrielrivas | 0:81fee41d95f1 | 97 | MessageQueue<uint8_t>* rxQueue, |
| gabrielrivas | 0:81fee41d95f1 | 98 | ThreadSafeArray_t *coilRegisters, |
| gabrielrivas | 0:81fee41d95f1 | 99 | ThreadSafeArray_t *inputRegisters, |
| gabrielrivas | 0:81fee41d95f1 | 100 | ThreadSafeArray_t *holdingRegisters); |
| gabrielrivas | 0:81fee41d95f1 | 101 | |
| gabrielrivas | 0:81fee41d95f1 | 102 | public: |
| gabrielrivas | 0:81fee41d95f1 | 103 | /** |
| gabrielrivas | 0:81fee41d95f1 | 104 | * @brief Function to start the Modbus RTU Slave engine. |
| gabrielrivas | 0:81fee41d95f1 | 105 | * @return void |
| gabrielrivas | 0:81fee41d95f1 | 106 | */ |
| gabrielrivas | 0:81fee41d95f1 | 107 | void trigger(void); |
| gabrielrivas | 0:81fee41d95f1 | 108 | |
| gabrielrivas | 0:81fee41d95f1 | 109 | /** |
| gabrielrivas | 0:81fee41d95f1 | 110 | * @brief Function to start the Modbus RTU Slave engine. |
| gabrielrivas | 0:81fee41d95f1 | 111 | * @return MbStatusTypes_t |
| gabrielrivas | 0:81fee41d95f1 | 112 | */ |
| gabrielrivas | 0:81fee41d95f1 | 113 | MbStatusTypes_t getStatus(void); |
| gabrielrivas | 0:81fee41d95f1 | 114 | void FSM(void); |
| gabrielrivas | 0:81fee41d95f1 | 115 | |
| gabrielrivas | 0:81fee41d95f1 | 116 | private: |
| gabrielrivas | 0:81fee41d95f1 | 117 | uint8_t readHoldingRegistersHandler(void); |
| gabrielrivas | 0:81fee41d95f1 | 118 | uint8_t readCoilRegistersHandler(void); |
| gabrielrivas | 0:81fee41d95f1 | 119 | uint8_t buildResponse(void); |
| gabrielrivas | 0:81fee41d95f1 | 120 | |
| gabrielrivas | 0:81fee41d95f1 | 121 | /** |
| gabrielrivas | 0:81fee41d95f1 | 122 | * @brief Function that computes the CRC of a Modbus message. |
| gabrielrivas | 0:81fee41d95f1 | 123 | * @param *data Pointer to the message data. |
| gabrielrivas | 0:81fee41d95f1 | 124 | * @param uint8_t Length of the message. |
| gabrielrivas | 0:81fee41d95f1 | 125 | * @return The CRC Code. |
| gabrielrivas | 0:81fee41d95f1 | 126 | */ |
| gabrielrivas | 0:81fee41d95f1 | 127 | uint16_t getCRC(uint8_t * data,uint8_t len); |
| gabrielrivas | 0:81fee41d95f1 | 128 | |
| gabrielrivas | 0:81fee41d95f1 | 129 | /** |
| gabrielrivas | 0:81fee41d95f1 | 130 | * @brief Verifies the CRC value of a message to determine it has been received correctly. |
| gabrielrivas | 0:81fee41d95f1 | 131 | * @param *data Pointer to the message data. |
| gabrielrivas | 0:81fee41d95f1 | 132 | * @return Returns 1 if the message has been well received, 0 otherwise. |
| gabrielrivas | 0:81fee41d95f1 | 133 | */ |
| gabrielrivas | 0:81fee41d95f1 | 134 | uint8_t checkMessageCRC(uint8_t * data); |
| gabrielrivas | 0:81fee41d95f1 | 135 | |
| gabrielrivas | 0:81fee41d95f1 | 136 | /** |
| gabrielrivas | 0:81fee41d95f1 | 137 | * @brief Function that appends the header and tail bytes for a response message. |
| gabrielrivas | 0:81fee41d95f1 | 138 | * @return void. |
| gabrielrivas | 0:81fee41d95f1 | 139 | */ |
| gabrielrivas | 0:81fee41d95f1 | 140 | void appendHeaderAndTailToMessage(void); |
| gabrielrivas | 0:81fee41d95f1 | 141 | |
| gabrielrivas | 0:81fee41d95f1 | 142 | /** |
| gabrielrivas | 0:81fee41d95f1 | 143 | * @brief Function that checks for error in the received message. |
| gabrielrivas | 0:81fee41d95f1 | 144 | * @param *array Safe array being processed depending on the modbus function. |
| gabrielrivas | 0:81fee41d95f1 | 145 | * @return uint8_t the error or success code. |
| gabrielrivas | 0:81fee41d95f1 | 146 | */ |
| gabrielrivas | 0:81fee41d95f1 | 147 | uint8_t checkReceivedMessageErrors(ThreadSafeArray_t *array); |
| gabrielrivas | 0:81fee41d95f1 | 148 | |
| gabrielrivas | 0:81fee41d95f1 | 149 | private: |
| gabrielrivas | 0:81fee41d95f1 | 150 | MbSlaveRTUStates_t m_state; |
| gabrielrivas | 0:81fee41d95f1 | 151 | MbSlaveRTUFrame_t m_frame; |
| gabrielrivas | 0:81fee41d95f1 | 152 | MbSlaveRTUControl_t m_control; |
| gabrielrivas | 0:81fee41d95f1 | 153 | MemoryMap_t m_memoryMap; |
| gabrielrivas | 0:81fee41d95f1 | 154 | MessageQueue<uint8_t>* m_bTxQueue; |
| gabrielrivas | 0:81fee41d95f1 | 155 | MessageQueue<uint8_t>* m_bRxQueue; |
| gabrielrivas | 0:81fee41d95f1 | 156 | uint8_t m_receivedMessage[MODBUS_MAX_LEN]; |
| gabrielrivas | 0:81fee41d95f1 | 157 | uint8_t m_responseMessage[MODBUS_MAX_LEN]; |
| gabrielrivas | 0:81fee41d95f1 | 158 | }; |
| gabrielrivas | 0:81fee41d95f1 | 159 | #endif |