Gabriel Rivas / ModbusSlaveRTU

Dependents:   Nucleo_modbus_protocol_test

Committer:
gabrielrivas
Date:
Mon Jan 19 08:21:11 2015 +0000
Revision:
4:9751b0a81ded
Parent:
3:71ae7fd3f2fa
Child:
5:7cec6597adee
Documentation added.

Who changed what in which revision?

UserRevisionLine numberNew 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 4:9751b0a81ded 39 /*! Status of the internal modbus FSM. */
gabrielrivas 4:9751b0a81ded 40 enum MbStatusTypes_t {
gabrielrivas 4:9751b0a81ded 41 LISTENING = 0x20, /**< Listening for incomming requests.*/
gabrielrivas 4:9751b0a81ded 42 PROCESSING = 0x21, /**< Processing received request.*/
gabrielrivas 4:9751b0a81ded 43 SENDING = 0x23 /**< Sending generated response.*/
gabrielrivas 4:9751b0a81ded 44 };
gabrielrivas 4:9751b0a81ded 45
gabrielrivas 4:9751b0a81ded 46 private:
gabrielrivas 0:81fee41d95f1 47 /*! Modbus response message bytes indexes. */
gabrielrivas 1:5efaa10b9a3f 48 enum MbByteIndex_t {
gabrielrivas 1:5efaa10b9a3f 49 ADDRESS = 0, /**< Modbus address position.*/
gabrielrivas 1:5efaa10b9a3f 50 FUNCTION = 1, /**< Modbus function position.*/
gabrielrivas 1:5efaa10b9a3f 51 BYTE_COUNT = 2, /**< Byte count high byte position.*/
gabrielrivas 1:5efaa10b9a3f 52 DATA_START = 3, /**< Returned data start position.*/
gabrielrivas 1:5efaa10b9a3f 53 BYTE_OFFSET = 2, /**< Starting register in bytes, high byte position.*/
gabrielrivas 1:5efaa10b9a3f 54 REGISTER_COUNT = 4 /**< Number of registers to be read, high byte position.*/
gabrielrivas 0:81fee41d95f1 55 };
gabrielrivas 0:81fee41d95f1 56
gabrielrivas 0:81fee41d95f1 57 /*! Modbus errors reported during message processing. */
gabrielrivas 0:81fee41d95f1 58 enum MbReceivedMessageErrors_t {
gabrielrivas 1:5efaa10b9a3f 59 NO_ERROR = 0x10, /**< No error.*/
gabrielrivas 1:5efaa10b9a3f 60 ADDRESS_ERROR = 0x11, /**< Wrong slave address.*/
gabrielrivas 1:5efaa10b9a3f 61 CRC_ERROR = 0x12, /**< CRC from received message doesn't match with locally calculated CRC.*/
gabrielrivas 1:5efaa10b9a3f 62 OFFSET_ERROR = 0x13, /**< Offset is out of range.*/
gabrielrivas 1:5efaa10b9a3f 63 BYTE_COUNT_ERROR = 0x14 /**< Byte count requested is out of range.*/
gabrielrivas 0:81fee41d95f1 64 };
gabrielrivas 4:9751b0a81ded 65
gabrielrivas 1:5efaa10b9a3f 66 /*! Internal modbus FSM states. */
gabrielrivas 0:81fee41d95f1 67 enum MbSlaveRTUStates_t {
gabrielrivas 1:5efaa10b9a3f 68 WAIT_REQUEST_MESSAGE = 0x00, /**< Idle while bytes are being received.*/
gabrielrivas 1:5efaa10b9a3f 69 GET_RECEIVED_BYTES = 0x01, /**< Copy received bytes into the internal buffer.*/
gabrielrivas 1:5efaa10b9a3f 70 BUILD_RESPONSE_MESSAGE = 0x02, /**< Building response message.*/
gabrielrivas 1:5efaa10b9a3f 71 TRANSMIT_RESPONSE_MESSAGE = 0x03 /**< Transmitting response message.*/
gabrielrivas 0:81fee41d95f1 72 };
gabrielrivas 0:81fee41d95f1 73
gabrielrivas 0:81fee41d95f1 74 /*! Modbus function codes. */
gabrielrivas 0:81fee41d95f1 75 enum MbFunctionCodes_t {
gabrielrivas 0:81fee41d95f1 76 READ_COIL_STATUS = 0x01, /**< Function to read a single coil status.*/
gabrielrivas 0:81fee41d95f1 77 READ_INPUT_STATUS = 0x02, /**< Function to read input register.*/
gabrielrivas 0:81fee41d95f1 78 READ_HOLDING_REGISTERS = 0x03, /**< Function to read one or more internal holding resgisters.*/
gabrielrivas 0:81fee41d95f1 79 READ_INPUT_REGISTERS = 0x04, /**< Function to read one or more input resgisters.*/
gabrielrivas 0:81fee41d95f1 80 FORCE_SINGLE_COIL = 0x05, /**< Function to write a value into a single discrete output.*/
gabrielrivas 0:81fee41d95f1 81 PRESET_SINGLE_REGISTER = 0x06, /**< Function to write a value into a single holding register.*/
gabrielrivas 0:81fee41d95f1 82 READ_EXCEPTION_STATUS = 0x07, /**< Function to request the value of the status byte.*/
gabrielrivas 0:81fee41d95f1 83 LOOPBACK_TEST = 0x08, /**< Function to test the communications interface. Returns the same message.*/
gabrielrivas 0:81fee41d95f1 84 FORCE_MULTIPLE_COILS = 0x0F /**< Function to set more than one coil to a given value*/
gabrielrivas 0:81fee41d95f1 85 };
gabrielrivas 0:81fee41d95f1 86
gabrielrivas 0:81fee41d95f1 87 /*! Modbus frame structure elements. */
gabrielrivas 0:81fee41d95f1 88 struct MbSlaveRTUFrame_t {
gabrielrivas 0:81fee41d95f1 89 uint8_t mAddress; /**< Slave device address.*/
gabrielrivas 0:81fee41d95f1 90 MbFunctionCodes_t mFunction; /**< Requested function of type MbFunctionCodes_t.*/
gabrielrivas 0:81fee41d95f1 91 uint16_t mOffset; /**< Offset in bytes from the starting address.*/
gabrielrivas 1:5efaa10b9a3f 92 uint16_t mByteCount; /**< Number of bytes to respond.*/
gabrielrivas 1:5efaa10b9a3f 93 uint8_t mCRCH; /**< CRC high byte.*/
gabrielrivas 1:5efaa10b9a3f 94 uint8_t mCRCL; /**< CRC low byte.*/
gabrielrivas 1:5efaa10b9a3f 95 uint16_t mSize; /**< Size of the frame in bytes.*/
gabrielrivas 0:81fee41d95f1 96 };
gabrielrivas 0:81fee41d95f1 97
gabrielrivas 1:5efaa10b9a3f 98 /*! Memory map structure. */
gabrielrivas 0:81fee41d95f1 99 struct MemoryMap_t {
gabrielrivas 1:5efaa10b9a3f 100 ThreadSafeArray_t *coilRegisters; /**< Pointer to the coil registers array.*/
gabrielrivas 1:5efaa10b9a3f 101 ThreadSafeArray_t *holdingRegisters; /**< Pointer to the holding registers array.*/
gabrielrivas 1:5efaa10b9a3f 102 ThreadSafeArray_t *inputRegisters; /**< Pointer to the input registers array.*/
gabrielrivas 0:81fee41d95f1 103 };
gabrielrivas 0:81fee41d95f1 104
gabrielrivas 0:81fee41d95f1 105 public:
gabrielrivas 0:81fee41d95f1 106 /**
gabrielrivas 1:5efaa10b9a3f 107 * Creates a Modbus Slave RTU object.
gabrielrivas 1:5efaa10b9a3f 108 * @param id Mosbus address.
gabrielrivas 1:5efaa10b9a3f 109 * @param txQueue Message queue to write modbus responses into.
gabrielrivas 1:5efaa10b9a3f 110 * @param rxQueue Message queue to read modbus requests from.
gabrielrivas 0:81fee41d95f1 111 * @param *coilRegisters Pointer to the memory space reserved for the coil registers.
gabrielrivas 0:81fee41d95f1 112 * @param *inputRegisters Pointer to the memory space reserved for the input registers.
gabrielrivas 0:81fee41d95f1 113 * @param *inputRegisters Pointer to the memory space reserved for the holding registers.
gabrielrivas 0:81fee41d95f1 114 * @return void
gabrielrivas 0:81fee41d95f1 115 */
gabrielrivas 0:81fee41d95f1 116 ModbusSlaveRTU( uint8_t id,
gabrielrivas 0:81fee41d95f1 117 MessageQueue<uint8_t>* txQueue,
gabrielrivas 0:81fee41d95f1 118 MessageQueue<uint8_t>* rxQueue,
gabrielrivas 0:81fee41d95f1 119 ThreadSafeArray_t *coilRegisters,
gabrielrivas 0:81fee41d95f1 120 ThreadSafeArray_t *inputRegisters,
gabrielrivas 0:81fee41d95f1 121 ThreadSafeArray_t *holdingRegisters);
gabrielrivas 0:81fee41d95f1 122
gabrielrivas 0:81fee41d95f1 123 public:
gabrielrivas 0:81fee41d95f1 124 /**
gabrielrivas 1:5efaa10b9a3f 125 * Function to start the Modbus RTU Slave engine.
gabrielrivas 0:81fee41d95f1 126 */
gabrielrivas 0:81fee41d95f1 127 void trigger(void);
gabrielrivas 0:81fee41d95f1 128
gabrielrivas 0:81fee41d95f1 129 /**
gabrielrivas 1:5efaa10b9a3f 130 * Gets the status of the internal FSM.
gabrielrivas 1:5efaa10b9a3f 131 * @return Status value as defined in MbStatusTypes_t.
gabrielrivas 0:81fee41d95f1 132 */
gabrielrivas 0:81fee41d95f1 133 MbStatusTypes_t getStatus(void);
gabrielrivas 1:5efaa10b9a3f 134
gabrielrivas 1:5efaa10b9a3f 135 /**
gabrielrivas 1:5efaa10b9a3f 136 * Internal FSM process.
gabrielrivas 1:5efaa10b9a3f 137 */
gabrielrivas 0:81fee41d95f1 138 void FSM(void);
gabrielrivas 0:81fee41d95f1 139
gabrielrivas 0:81fee41d95f1 140 private:
gabrielrivas 1:5efaa10b9a3f 141 /**
gabrielrivas 1:5efaa10b9a3f 142 * Handler for read holding registers function request.
gabrielrivas 1:5efaa10b9a3f 143 * @return Error or success code as defined in MbReceivedMessageErrors_t.
gabrielrivas 1:5efaa10b9a3f 144 */
gabrielrivas 1:5efaa10b9a3f 145 MbReceivedMessageErrors_t readHoldingRegistersHandler(void);
gabrielrivas 1:5efaa10b9a3f 146
gabrielrivas 1:5efaa10b9a3f 147 /**
gabrielrivas 1:5efaa10b9a3f 148 * Handler for read coil registers function request.
gabrielrivas 1:5efaa10b9a3f 149 * @return Error or success code as defined in MbReceivedMessageErrors_t.
gabrielrivas 1:5efaa10b9a3f 150 */
gabrielrivas 1:5efaa10b9a3f 151 MbReceivedMessageErrors_t readCoilRegistersHandler(void);
gabrielrivas 1:5efaa10b9a3f 152
gabrielrivas 1:5efaa10b9a3f 153 /**
gabrielrivas 1:5efaa10b9a3f 154 * Builds response message.
gabrielrivas 1:5efaa10b9a3f 155 * @return Error or success code as defined in MbReceivedMessageErrors_t.
gabrielrivas 1:5efaa10b9a3f 156 */
gabrielrivas 1:5efaa10b9a3f 157 MbReceivedMessageErrors_t buildResponse(void);
gabrielrivas 0:81fee41d95f1 158
gabrielrivas 0:81fee41d95f1 159 /**
gabrielrivas 1:5efaa10b9a3f 160 * Function that computes the CRC of a Modbus message.
gabrielrivas 0:81fee41d95f1 161 * @param *data Pointer to the message data.
gabrielrivas 0:81fee41d95f1 162 * @param uint8_t Length of the message.
gabrielrivas 0:81fee41d95f1 163 * @return The CRC Code.
gabrielrivas 0:81fee41d95f1 164 */
gabrielrivas 0:81fee41d95f1 165 uint16_t getCRC(uint8_t * data,uint8_t len);
gabrielrivas 0:81fee41d95f1 166
gabrielrivas 0:81fee41d95f1 167 /**
gabrielrivas 1:5efaa10b9a3f 168 * Verifies the CRC value of a message to determine it has been received correctly.
gabrielrivas 0:81fee41d95f1 169 * @param *data Pointer to the message data.
gabrielrivas 0:81fee41d95f1 170 * @return Returns 1 if the message has been well received, 0 otherwise.
gabrielrivas 0:81fee41d95f1 171 */
gabrielrivas 0:81fee41d95f1 172 uint8_t checkMessageCRC(uint8_t * data);
gabrielrivas 0:81fee41d95f1 173
gabrielrivas 0:81fee41d95f1 174 /**
gabrielrivas 1:5efaa10b9a3f 175 * Function that appends the header and tail bytes for a response message.
gabrielrivas 0:81fee41d95f1 176 * @return void.
gabrielrivas 0:81fee41d95f1 177 */
gabrielrivas 0:81fee41d95f1 178 void appendHeaderAndTailToMessage(void);
gabrielrivas 0:81fee41d95f1 179
gabrielrivas 0:81fee41d95f1 180 /**
gabrielrivas 1:5efaa10b9a3f 181 * Function that checks for error in the received message.
gabrielrivas 0:81fee41d95f1 182 * @param *array Safe array being processed depending on the modbus function.
gabrielrivas 1:5efaa10b9a3f 183 * @return The error or success code as defined in MbReceivedMessageErrors_t.
gabrielrivas 0:81fee41d95f1 184 */
gabrielrivas 1:5efaa10b9a3f 185 MbReceivedMessageErrors_t checkReceivedMessageErrors(ThreadSafeArray_t *array);
gabrielrivas 0:81fee41d95f1 186
gabrielrivas 0:81fee41d95f1 187 private:
gabrielrivas 1:5efaa10b9a3f 188 /** Internal state of the modbus FSM.
gabrielrivas 1:5efaa10b9a3f 189 */
gabrielrivas 0:81fee41d95f1 190 MbSlaveRTUStates_t m_state;
gabrielrivas 1:5efaa10b9a3f 191
gabrielrivas 1:5efaa10b9a3f 192 /** Response frame.
gabrielrivas 1:5efaa10b9a3f 193 */
gabrielrivas 0:81fee41d95f1 194 MbSlaveRTUFrame_t m_frame;
gabrielrivas 1:5efaa10b9a3f 195
gabrielrivas 1:5efaa10b9a3f 196 /** Modbus address.
gabrielrivas 1:5efaa10b9a3f 197 */
gabrielrivas 1:5efaa10b9a3f 198 uint8_t m_address;
gabrielrivas 1:5efaa10b9a3f 199
gabrielrivas 1:5efaa10b9a3f 200 /** Modbus process status.
gabrielrivas 1:5efaa10b9a3f 201 */
gabrielrivas 1:5efaa10b9a3f 202 MbStatusTypes_t m_status;
gabrielrivas 1:5efaa10b9a3f 203
gabrielrivas 1:5efaa10b9a3f 204 /** Memory map for registers.
gabrielrivas 1:5efaa10b9a3f 205 */
gabrielrivas 0:81fee41d95f1 206 MemoryMap_t m_memoryMap;
gabrielrivas 1:5efaa10b9a3f 207
gabrielrivas 1:5efaa10b9a3f 208 /** Queue to write response data.
gabrielrivas 1:5efaa10b9a3f 209 */
gabrielrivas 0:81fee41d95f1 210 MessageQueue<uint8_t>* m_bTxQueue;
gabrielrivas 1:5efaa10b9a3f 211
gabrielrivas 1:5efaa10b9a3f 212 /** Queue to read incomming requests from.
gabrielrivas 1:5efaa10b9a3f 213 */
gabrielrivas 0:81fee41d95f1 214 MessageQueue<uint8_t>* m_bRxQueue;
gabrielrivas 1:5efaa10b9a3f 215
gabrielrivas 1:5efaa10b9a3f 216 /** Internal byte array to copy incomming requests.
gabrielrivas 1:5efaa10b9a3f 217 */
gabrielrivas 0:81fee41d95f1 218 uint8_t m_receivedMessage[MODBUS_MAX_LEN];
gabrielrivas 1:5efaa10b9a3f 219
gabrielrivas 1:5efaa10b9a3f 220 /** Internal byte array to generate responses.
gabrielrivas 1:5efaa10b9a3f 221 */
gabrielrivas 0:81fee41d95f1 222 uint8_t m_responseMessage[MODBUS_MAX_LEN];
gabrielrivas 0:81fee41d95f1 223 };
gabrielrivas 0:81fee41d95f1 224 #endif