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@3:71ae7fd3f2fa, 2015-01-19 (annotated)
- Committer:
- gabrielrivas
- Date:
- Mon Jan 19 08:12:28 2015 +0000
- Revision:
- 3:71ae7fd3f2fa
- Parent:
- 2:f028bdcd4814
- Child:
- 4:9751b0a81ded
Documentation added.;
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| gabrielrivas | 2:f028bdcd4814 | 1 | /** Modbus Slave RTU |
| gabrielrivas | 1:5efaa10b9a3f | 2 | * Copyright (c) 2015 Gabriel Rivas |
| gabrielrivas | 1:5efaa10b9a3f | 3 | * |
| gabrielrivas | 1:5efaa10b9a3f | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| gabrielrivas | 1:5efaa10b9a3f | 5 | * you may not use this file except in compliance with the License. |
| gabrielrivas | 1:5efaa10b9a3f | 6 | * You may obtain a copy of the License at |
| gabrielrivas | 1:5efaa10b9a3f | 7 | * |
| gabrielrivas | 1:5efaa10b9a3f | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| gabrielrivas | 1:5efaa10b9a3f | 9 | * |
| gabrielrivas | 1:5efaa10b9a3f | 10 | * Unless required by applicable law or agreed to in writing, software |
| gabrielrivas | 1:5efaa10b9a3f | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| gabrielrivas | 1:5efaa10b9a3f | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| gabrielrivas | 1:5efaa10b9a3f | 13 | * See the License for the specific language governing permissions and |
| gabrielrivas | 1:5efaa10b9a3f | 14 | * limitations under the License. |
| gabrielrivas | 1:5efaa10b9a3f | 15 | */ |
| gabrielrivas | 1:5efaa10b9a3f | 16 | |
| gabrielrivas | 0:81fee41d95f1 | 17 | #ifndef _MODBUS_SLAVE_RTU_H_ |
| gabrielrivas | 0:81fee41d95f1 | 18 | #define _MODBUS_SLAVE_RTU_H_ |
| gabrielrivas | 0:81fee41d95f1 | 19 | |
| gabrielrivas | 0:81fee41d95f1 | 20 | #include "mbed.h" |
| gabrielrivas | 0:81fee41d95f1 | 21 | #include "rtos.h" |
| gabrielrivas | 0:81fee41d95f1 | 22 | #include "MessageQueue.h" |
| gabrielrivas | 0:81fee41d95f1 | 23 | |
| gabrielrivas | 0:81fee41d95f1 | 24 | #define MODBUS_MAX_LEN (256) |
| gabrielrivas | 0:81fee41d95f1 | 25 | |
| gabrielrivas | 0:81fee41d95f1 | 26 | struct ThreadSafeArray_t { |
| gabrielrivas | 0:81fee41d95f1 | 27 | Mutex mutex; |
| gabrielrivas | 0:81fee41d95f1 | 28 | uint8_t *data; |
| gabrielrivas | 0:81fee41d95f1 | 29 | uint32_t length; |
| gabrielrivas | 0:81fee41d95f1 | 30 | }; |
| gabrielrivas | 0:81fee41d95f1 | 31 | |
| gabrielrivas | 3:71ae7fd3f2fa | 32 | /** |
| gabrielrivas | 3:71ae7fd3f2fa | 33 | * Modbus RTU class for slave devices. It shares data with other software components via a Message queue object, |
| gabrielrivas | 3:71ae7fd3f2fa | 34 | * and can exist more than one Modbus Slave RTU instances in a application program. |
| gabrielrivas | 3:71ae7fd3f2fa | 35 | */ |
| gabrielrivas | 0:81fee41d95f1 | 36 | class ModbusSlaveRTU |
| gabrielrivas | 0:81fee41d95f1 | 37 | { |
| gabrielrivas | 0:81fee41d95f1 | 38 | public: |
| gabrielrivas | 0:81fee41d95f1 | 39 | /*! Modbus response message bytes indexes. */ |
| gabrielrivas | 1:5efaa10b9a3f | 40 | enum MbByteIndex_t { |
| gabrielrivas | 1:5efaa10b9a3f | 41 | ADDRESS = 0, /**< Modbus address position.*/ |
| gabrielrivas | 1:5efaa10b9a3f | 42 | FUNCTION = 1, /**< Modbus function position.*/ |
| gabrielrivas | 1:5efaa10b9a3f | 43 | BYTE_COUNT = 2, /**< Byte count high byte position.*/ |
| gabrielrivas | 1:5efaa10b9a3f | 44 | DATA_START = 3, /**< Returned data start position.*/ |
| gabrielrivas | 1:5efaa10b9a3f | 45 | BYTE_OFFSET = 2, /**< Starting register in bytes, high byte position.*/ |
| gabrielrivas | 1:5efaa10b9a3f | 46 | REGISTER_COUNT = 4 /**< Number of registers to be read, high byte position.*/ |
| gabrielrivas | 0:81fee41d95f1 | 47 | }; |
| gabrielrivas | 0:81fee41d95f1 | 48 | |
| gabrielrivas | 0:81fee41d95f1 | 49 | /*! Modbus errors reported during message processing. */ |
| gabrielrivas | 0:81fee41d95f1 | 50 | enum MbReceivedMessageErrors_t { |
| gabrielrivas | 1:5efaa10b9a3f | 51 | NO_ERROR = 0x10, /**< No error.*/ |
| gabrielrivas | 1:5efaa10b9a3f | 52 | ADDRESS_ERROR = 0x11, /**< Wrong slave address.*/ |
| gabrielrivas | 1:5efaa10b9a3f | 53 | CRC_ERROR = 0x12, /**< CRC from received message doesn't match with locally calculated CRC.*/ |
| gabrielrivas | 1:5efaa10b9a3f | 54 | OFFSET_ERROR = 0x13, /**< Offset is out of range.*/ |
| gabrielrivas | 1:5efaa10b9a3f | 55 | BYTE_COUNT_ERROR = 0x14 /**< Byte count requested is out of range.*/ |
| gabrielrivas | 0:81fee41d95f1 | 56 | }; |
| gabrielrivas | 0:81fee41d95f1 | 57 | |
| gabrielrivas | 1:5efaa10b9a3f | 58 | /*! Status of the internal modbus FSM. */ |
| gabrielrivas | 0:81fee41d95f1 | 59 | enum MbStatusTypes_t { |
| gabrielrivas | 1:5efaa10b9a3f | 60 | LISTENING = 0x20, /**< Listening for incomming requests.*/ |
| gabrielrivas | 1:5efaa10b9a3f | 61 | PROCESSING = 0x21, /**< Processing received request.*/ |
| gabrielrivas | 1:5efaa10b9a3f | 62 | SENDING = 0x23 /**< Sending generated response.*/ |
| gabrielrivas | 0:81fee41d95f1 | 63 | }; |
| gabrielrivas | 0:81fee41d95f1 | 64 | |
| gabrielrivas | 1:5efaa10b9a3f | 65 | /*! Internal modbus FSM states. */ |
| gabrielrivas | 0:81fee41d95f1 | 66 | enum MbSlaveRTUStates_t { |
| gabrielrivas | 1:5efaa10b9a3f | 67 | WAIT_REQUEST_MESSAGE = 0x00, /**< Idle while bytes are being received.*/ |
| gabrielrivas | 1:5efaa10b9a3f | 68 | GET_RECEIVED_BYTES = 0x01, /**< Copy received bytes into the internal buffer.*/ |
| gabrielrivas | 1:5efaa10b9a3f | 69 | BUILD_RESPONSE_MESSAGE = 0x02, /**< Building response message.*/ |
| gabrielrivas | 1:5efaa10b9a3f | 70 | TRANSMIT_RESPONSE_MESSAGE = 0x03 /**< Transmitting response message.*/ |
| gabrielrivas | 0:81fee41d95f1 | 71 | }; |
| gabrielrivas | 0:81fee41d95f1 | 72 | |
| gabrielrivas | 0:81fee41d95f1 | 73 | /*! Modbus function codes. */ |
| gabrielrivas | 0:81fee41d95f1 | 74 | enum MbFunctionCodes_t { |
| gabrielrivas | 0:81fee41d95f1 | 75 | READ_COIL_STATUS = 0x01, /**< Function to read a single coil status.*/ |
| gabrielrivas | 0:81fee41d95f1 | 76 | READ_INPUT_STATUS = 0x02, /**< Function to read input register.*/ |
| gabrielrivas | 0:81fee41d95f1 | 77 | READ_HOLDING_REGISTERS = 0x03, /**< Function to read one or more internal holding resgisters.*/ |
| gabrielrivas | 0:81fee41d95f1 | 78 | READ_INPUT_REGISTERS = 0x04, /**< Function to read one or more input resgisters.*/ |
| gabrielrivas | 0:81fee41d95f1 | 79 | FORCE_SINGLE_COIL = 0x05, /**< Function to write a value into a single discrete output.*/ |
| gabrielrivas | 0:81fee41d95f1 | 80 | PRESET_SINGLE_REGISTER = 0x06, /**< Function to write a value into a single holding register.*/ |
| gabrielrivas | 0:81fee41d95f1 | 81 | READ_EXCEPTION_STATUS = 0x07, /**< Function to request the value of the status byte.*/ |
| gabrielrivas | 0:81fee41d95f1 | 82 | LOOPBACK_TEST = 0x08, /**< Function to test the communications interface. Returns the same message.*/ |
| gabrielrivas | 0:81fee41d95f1 | 83 | FORCE_MULTIPLE_COILS = 0x0F /**< Function to set more than one coil to a given value*/ |
| gabrielrivas | 0:81fee41d95f1 | 84 | }; |
| gabrielrivas | 0:81fee41d95f1 | 85 | |
| gabrielrivas | 0:81fee41d95f1 | 86 | /*! Modbus frame structure elements. */ |
| gabrielrivas | 0:81fee41d95f1 | 87 | struct MbSlaveRTUFrame_t { |
| gabrielrivas | 0:81fee41d95f1 | 88 | uint8_t mAddress; /**< Slave device address.*/ |
| gabrielrivas | 0:81fee41d95f1 | 89 | MbFunctionCodes_t mFunction; /**< Requested function of type MbFunctionCodes_t.*/ |
| gabrielrivas | 0:81fee41d95f1 | 90 | uint16_t mOffset; /**< Offset in bytes from the starting address.*/ |
| gabrielrivas | 1:5efaa10b9a3f | 91 | uint16_t mByteCount; /**< Number of bytes to respond.*/ |
| gabrielrivas | 1:5efaa10b9a3f | 92 | uint8_t mCRCH; /**< CRC high byte.*/ |
| gabrielrivas | 1:5efaa10b9a3f | 93 | uint8_t mCRCL; /**< CRC low byte.*/ |
| gabrielrivas | 1:5efaa10b9a3f | 94 | uint16_t mSize; /**< Size of the frame in bytes.*/ |
| gabrielrivas | 0:81fee41d95f1 | 95 | }; |
| gabrielrivas | 0:81fee41d95f1 | 96 | |
| gabrielrivas | 1:5efaa10b9a3f | 97 | /*! Memory map structure. */ |
| gabrielrivas | 0:81fee41d95f1 | 98 | struct MemoryMap_t { |
| gabrielrivas | 1:5efaa10b9a3f | 99 | ThreadSafeArray_t *coilRegisters; /**< Pointer to the coil registers array.*/ |
| gabrielrivas | 1:5efaa10b9a3f | 100 | ThreadSafeArray_t *holdingRegisters; /**< Pointer to the holding registers array.*/ |
| gabrielrivas | 1:5efaa10b9a3f | 101 | ThreadSafeArray_t *inputRegisters; /**< Pointer to the input registers array.*/ |
| gabrielrivas | 0:81fee41d95f1 | 102 | }; |
| gabrielrivas | 0:81fee41d95f1 | 103 | |
| gabrielrivas | 0:81fee41d95f1 | 104 | public: |
| gabrielrivas | 0:81fee41d95f1 | 105 | /** |
| gabrielrivas | 1:5efaa10b9a3f | 106 | * Creates a Modbus Slave RTU object. |
| gabrielrivas | 1:5efaa10b9a3f | 107 | * @param id Mosbus address. |
| gabrielrivas | 1:5efaa10b9a3f | 108 | * @param txQueue Message queue to write modbus responses into. |
| gabrielrivas | 1:5efaa10b9a3f | 109 | * @param rxQueue Message queue to read modbus requests from. |
| gabrielrivas | 0:81fee41d95f1 | 110 | * @param *coilRegisters Pointer to the memory space reserved for the coil registers. |
| gabrielrivas | 0:81fee41d95f1 | 111 | * @param *inputRegisters Pointer to the memory space reserved for the input registers. |
| gabrielrivas | 0:81fee41d95f1 | 112 | * @param *inputRegisters Pointer to the memory space reserved for the holding registers. |
| gabrielrivas | 0:81fee41d95f1 | 113 | * @return void |
| gabrielrivas | 0:81fee41d95f1 | 114 | */ |
| gabrielrivas | 0:81fee41d95f1 | 115 | ModbusSlaveRTU( uint8_t id, |
| gabrielrivas | 0:81fee41d95f1 | 116 | MessageQueue<uint8_t>* txQueue, |
| gabrielrivas | 0:81fee41d95f1 | 117 | MessageQueue<uint8_t>* rxQueue, |
| gabrielrivas | 0:81fee41d95f1 | 118 | ThreadSafeArray_t *coilRegisters, |
| gabrielrivas | 0:81fee41d95f1 | 119 | ThreadSafeArray_t *inputRegisters, |
| gabrielrivas | 0:81fee41d95f1 | 120 | ThreadSafeArray_t *holdingRegisters); |
| gabrielrivas | 0:81fee41d95f1 | 121 | |
| gabrielrivas | 0:81fee41d95f1 | 122 | public: |
| gabrielrivas | 0:81fee41d95f1 | 123 | /** |
| gabrielrivas | 1:5efaa10b9a3f | 124 | * Function to start the Modbus RTU Slave engine. |
| gabrielrivas | 0:81fee41d95f1 | 125 | */ |
| gabrielrivas | 0:81fee41d95f1 | 126 | void trigger(void); |
| gabrielrivas | 0:81fee41d95f1 | 127 | |
| gabrielrivas | 0:81fee41d95f1 | 128 | /** |
| gabrielrivas | 1:5efaa10b9a3f | 129 | * Gets the status of the internal FSM. |
| gabrielrivas | 1:5efaa10b9a3f | 130 | * @return Status value as defined in MbStatusTypes_t. |
| gabrielrivas | 0:81fee41d95f1 | 131 | */ |
| gabrielrivas | 0:81fee41d95f1 | 132 | MbStatusTypes_t getStatus(void); |
| gabrielrivas | 1:5efaa10b9a3f | 133 | |
| gabrielrivas | 1:5efaa10b9a3f | 134 | /** |
| gabrielrivas | 1:5efaa10b9a3f | 135 | * Internal FSM process. |
| gabrielrivas | 1:5efaa10b9a3f | 136 | */ |
| gabrielrivas | 0:81fee41d95f1 | 137 | void FSM(void); |
| gabrielrivas | 0:81fee41d95f1 | 138 | |
| gabrielrivas | 0:81fee41d95f1 | 139 | private: |
| gabrielrivas | 1:5efaa10b9a3f | 140 | /** |
| gabrielrivas | 1:5efaa10b9a3f | 141 | * Handler for read holding registers function request. |
| gabrielrivas | 1:5efaa10b9a3f | 142 | * @return Error or success code as defined in MbReceivedMessageErrors_t. |
| gabrielrivas | 1:5efaa10b9a3f | 143 | */ |
| gabrielrivas | 1:5efaa10b9a3f | 144 | MbReceivedMessageErrors_t readHoldingRegistersHandler(void); |
| gabrielrivas | 1:5efaa10b9a3f | 145 | |
| gabrielrivas | 1:5efaa10b9a3f | 146 | /** |
| gabrielrivas | 1:5efaa10b9a3f | 147 | * Handler for read coil registers function request. |
| gabrielrivas | 1:5efaa10b9a3f | 148 | * @return Error or success code as defined in MbReceivedMessageErrors_t. |
| gabrielrivas | 1:5efaa10b9a3f | 149 | */ |
| gabrielrivas | 1:5efaa10b9a3f | 150 | MbReceivedMessageErrors_t readCoilRegistersHandler(void); |
| gabrielrivas | 1:5efaa10b9a3f | 151 | |
| gabrielrivas | 1:5efaa10b9a3f | 152 | /** |
| gabrielrivas | 1:5efaa10b9a3f | 153 | * Builds response message. |
| gabrielrivas | 1:5efaa10b9a3f | 154 | * @return Error or success code as defined in MbReceivedMessageErrors_t. |
| gabrielrivas | 1:5efaa10b9a3f | 155 | */ |
| gabrielrivas | 1:5efaa10b9a3f | 156 | MbReceivedMessageErrors_t buildResponse(void); |
| gabrielrivas | 0:81fee41d95f1 | 157 | |
| gabrielrivas | 0:81fee41d95f1 | 158 | /** |
| gabrielrivas | 1:5efaa10b9a3f | 159 | * Function that computes the CRC of a Modbus message. |
| gabrielrivas | 0:81fee41d95f1 | 160 | * @param *data Pointer to the message data. |
| gabrielrivas | 0:81fee41d95f1 | 161 | * @param uint8_t Length of the message. |
| gabrielrivas | 0:81fee41d95f1 | 162 | * @return The CRC Code. |
| gabrielrivas | 0:81fee41d95f1 | 163 | */ |
| gabrielrivas | 0:81fee41d95f1 | 164 | uint16_t getCRC(uint8_t * data,uint8_t len); |
| gabrielrivas | 0:81fee41d95f1 | 165 | |
| gabrielrivas | 0:81fee41d95f1 | 166 | /** |
| gabrielrivas | 1:5efaa10b9a3f | 167 | * Verifies the CRC value of a message to determine it has been received correctly. |
| gabrielrivas | 0:81fee41d95f1 | 168 | * @param *data Pointer to the message data. |
| gabrielrivas | 0:81fee41d95f1 | 169 | * @return Returns 1 if the message has been well received, 0 otherwise. |
| gabrielrivas | 0:81fee41d95f1 | 170 | */ |
| gabrielrivas | 0:81fee41d95f1 | 171 | uint8_t checkMessageCRC(uint8_t * data); |
| gabrielrivas | 0:81fee41d95f1 | 172 | |
| gabrielrivas | 0:81fee41d95f1 | 173 | /** |
| gabrielrivas | 1:5efaa10b9a3f | 174 | * Function that appends the header and tail bytes for a response message. |
| gabrielrivas | 0:81fee41d95f1 | 175 | * @return void. |
| gabrielrivas | 0:81fee41d95f1 | 176 | */ |
| gabrielrivas | 0:81fee41d95f1 | 177 | void appendHeaderAndTailToMessage(void); |
| gabrielrivas | 0:81fee41d95f1 | 178 | |
| gabrielrivas | 0:81fee41d95f1 | 179 | /** |
| gabrielrivas | 1:5efaa10b9a3f | 180 | * Function that checks for error in the received message. |
| gabrielrivas | 0:81fee41d95f1 | 181 | * @param *array Safe array being processed depending on the modbus function. |
| gabrielrivas | 1:5efaa10b9a3f | 182 | * @return The error or success code as defined in MbReceivedMessageErrors_t. |
| gabrielrivas | 0:81fee41d95f1 | 183 | */ |
| gabrielrivas | 1:5efaa10b9a3f | 184 | MbReceivedMessageErrors_t checkReceivedMessageErrors(ThreadSafeArray_t *array); |
| gabrielrivas | 0:81fee41d95f1 | 185 | |
| gabrielrivas | 0:81fee41d95f1 | 186 | private: |
| gabrielrivas | 1:5efaa10b9a3f | 187 | /** Internal state of the modbus FSM. |
| gabrielrivas | 1:5efaa10b9a3f | 188 | */ |
| gabrielrivas | 0:81fee41d95f1 | 189 | MbSlaveRTUStates_t m_state; |
| gabrielrivas | 1:5efaa10b9a3f | 190 | |
| gabrielrivas | 1:5efaa10b9a3f | 191 | /** Response frame. |
| gabrielrivas | 1:5efaa10b9a3f | 192 | */ |
| gabrielrivas | 0:81fee41d95f1 | 193 | MbSlaveRTUFrame_t m_frame; |
| gabrielrivas | 1:5efaa10b9a3f | 194 | |
| gabrielrivas | 1:5efaa10b9a3f | 195 | /** Modbus address. |
| gabrielrivas | 1:5efaa10b9a3f | 196 | */ |
| gabrielrivas | 1:5efaa10b9a3f | 197 | uint8_t m_address; |
| gabrielrivas | 1:5efaa10b9a3f | 198 | |
| gabrielrivas | 1:5efaa10b9a3f | 199 | /** Modbus process status. |
| gabrielrivas | 1:5efaa10b9a3f | 200 | */ |
| gabrielrivas | 1:5efaa10b9a3f | 201 | MbStatusTypes_t m_status; |
| gabrielrivas | 1:5efaa10b9a3f | 202 | |
| gabrielrivas | 1:5efaa10b9a3f | 203 | /** Memory map for registers. |
| gabrielrivas | 1:5efaa10b9a3f | 204 | */ |
| gabrielrivas | 0:81fee41d95f1 | 205 | MemoryMap_t m_memoryMap; |
| gabrielrivas | 1:5efaa10b9a3f | 206 | |
| gabrielrivas | 1:5efaa10b9a3f | 207 | /** Queue to write response data. |
| gabrielrivas | 1:5efaa10b9a3f | 208 | */ |
| gabrielrivas | 0:81fee41d95f1 | 209 | MessageQueue<uint8_t>* m_bTxQueue; |
| gabrielrivas | 1:5efaa10b9a3f | 210 | |
| gabrielrivas | 1:5efaa10b9a3f | 211 | /** Queue to read incomming requests from. |
| gabrielrivas | 1:5efaa10b9a3f | 212 | */ |
| gabrielrivas | 0:81fee41d95f1 | 213 | MessageQueue<uint8_t>* m_bRxQueue; |
| gabrielrivas | 1:5efaa10b9a3f | 214 | |
| gabrielrivas | 1:5efaa10b9a3f | 215 | /** Internal byte array to copy incomming requests. |
| gabrielrivas | 1:5efaa10b9a3f | 216 | */ |
| gabrielrivas | 0:81fee41d95f1 | 217 | uint8_t m_receivedMessage[MODBUS_MAX_LEN]; |
| gabrielrivas | 1:5efaa10b9a3f | 218 | |
| gabrielrivas | 1:5efaa10b9a3f | 219 | /** Internal byte array to generate responses. |
| gabrielrivas | 1:5efaa10b9a3f | 220 | */ |
| gabrielrivas | 0:81fee41d95f1 | 221 | uint8_t m_responseMessage[MODBUS_MAX_LEN]; |
| gabrielrivas | 0:81fee41d95f1 | 222 | }; |
| gabrielrivas | 0:81fee41d95f1 | 223 | #endif |