Gabriel Rivas / ModbusSlaveRTU

Dependents:   Nucleo_modbus_protocol_test

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