Gabriel Rivas / ModbusSlaveRTU

Dependents:   Nucleo_modbus_protocol_test

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ModbusSlaveRTU.h Source File

ModbusSlaveRTU.h

00001 /** Modbus Slave RTU
00002  * Copyright (c) 2015 Gabriel Rivas
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #ifndef _MODBUS_SLAVE_RTU_H_
00018 #define _MODBUS_SLAVE_RTU_H_
00019 
00020 #include "mbed.h"
00021 #include "rtos.h"
00022 #include "MessageQueue.h"
00023 
00024 #define MODBUS_MAX_LEN (256)
00025 
00026 struct ThreadSafeArray_t {
00027     Mutex mutex;
00028     uint8_t *data;
00029     uint32_t length;
00030 };
00031 
00032 /**
00033  * Modbus RTU class for slave devices. It shares data with other software components via a Message queue object, 
00034  * and can exist more than one Modbus Slave RTU instances in a application program.
00035  */
00036 class ModbusSlaveRTU
00037 {
00038 public:
00039     /*! Status of the internal modbus FSM. */
00040     enum MbStatusTypes_t  {
00041         LISTENING  = 0x20, /**< Listening for incomming requests.*/
00042         PROCESSING = 0x21, /**< Processing received request.*/
00043         SENDING    = 0x23  /**< Sending generated response.*/
00044     };
00045     
00046 private:    
00047     /*! Modbus response message bytes indexes. */
00048     enum MbByteIndex_t {
00049         ADDRESS         = 0x00, /**< Modbus address position.*/
00050         FUNCTION        = 0x01, /**< Modbus function position.*/
00051         BYTE_COUNT      = 0x02, /**< Byte count high byte position.*/
00052         DATA_START      = 0x03, /**< Returned data start position.*/
00053         BYTE_OFFSET     = 0x02, /**< Starting register in bytes, high byte position.*/
00054         REGISTER_COUNT  = 0x04  /**< Number of registers to be read, high byte position.*/
00055     };
00056 
00057     /*! Modbus errors reported during message processing. */
00058     enum MbReceivedMessageErrors_t {
00059         NO_ERROR         = 0x10, /**< No error.*/
00060         ADDRESS_ERROR    = 0x11, /**< Wrong slave address.*/
00061         CRC_ERROR        = 0x12, /**< CRC from received message doesn't match with locally calculated CRC.*/
00062         OFFSET_ERROR     = 0x13, /**< Offset is out of range.*/
00063         BYTE_COUNT_ERROR = 0x14  /**< Byte count requested is out of range.*/
00064     };
00065     
00066     /*! Internal modbus FSM states. */
00067     enum MbSlaveRTUStates_t {
00068         WAIT_REQUEST_MESSAGE      = 0x00, /**< Idle while bytes are being received.*/
00069         GET_RECEIVED_BYTES        = 0x01, /**< Copy received bytes into the internal buffer.*/
00070         BUILD_RESPONSE_MESSAGE    = 0x02, /**< Building response message.*/
00071         TRANSMIT_RESPONSE_MESSAGE = 0x03  /**< Transmitting response message.*/
00072     };
00073 
00074     /*! Modbus function codes. */
00075     enum MbFunctionCodes_t {
00076         READ_COIL_STATUS        = 0x01, /**< Function to read a single coil status.*/
00077         READ_INPUT_STATUS       = 0x02, /**< Function to read input register.*/
00078         READ_HOLDING_REGISTERS  = 0x03, /**< Function to read one or more internal holding resgisters.*/
00079         READ_INPUT_REGISTERS    = 0x04, /**< Function to read one or more input resgisters.*/
00080         FORCE_SINGLE_COIL       = 0x05, /**< Function to write a value into a single discrete output.*/
00081         PRESET_SINGLE_REGISTER  = 0x06, /**< Function to write a value into a single holding register.*/
00082         READ_EXCEPTION_STATUS   = 0x07, /**< Function to request the value of the status byte.*/
00083         LOOPBACK_TEST           = 0x08, /**< Function to test the communications interface. Returns the same message.*/
00084         FORCE_MULTIPLE_COILS    = 0x0F  /**< Function to set more than one coil to a given value*/
00085     };
00086 
00087     /*! Modbus frame structure elements. */
00088     struct MbSlaveRTUFrame_t {
00089         uint8_t mAddress;             /**< Slave device address.*/
00090         MbFunctionCodes_t mFunction;  /**< Requested function of type MbFunctionCodes_t.*/
00091         uint16_t mOffset;             /**< Offset in bytes from the starting address.*/
00092         uint16_t mByteCount;          /**< Number of bytes to respond.*/
00093         uint8_t mCRCH;                /**< CRC high byte.*/
00094         uint8_t  mCRCL;               /**< CRC low byte.*/
00095         uint16_t mSize;               /**< Size of the frame in bytes.*/
00096     };
00097 
00098     /*! Memory map structure. */
00099     struct MemoryMap_t {
00100         ThreadSafeArray_t *coilRegisters;    /**< Pointer to the coil registers array.*/
00101         ThreadSafeArray_t *holdingRegisters; /**< Pointer to the holding registers array.*/
00102         ThreadSafeArray_t *inputRegisters;   /**< Pointer to the input registers array.*/
00103     };
00104 
00105 public:
00106     /**
00107      * Creates a Modbus Slave RTU object.
00108      * @param id Mosbus address.
00109      * @param txQueue Message queue to write modbus responses into.
00110      * @param rxQueue Message queue to read modbus requests from.     
00111      * @param *coilRegisters Pointer to the memory space reserved for the coil registers.
00112      * @param *inputRegisters Pointer to the memory space reserved for the input registers.
00113      * @param *inputRegisters Pointer to the memory space reserved for the holding registers.
00114      */
00115     ModbusSlaveRTU( uint8_t id,
00116                     MessageQueue<uint8_t>* txQueue,
00117                     MessageQueue<uint8_t>* rxQueue,
00118                     ThreadSafeArray_t *coilRegisters,
00119                     ThreadSafeArray_t *inputRegisters,
00120                     ThreadSafeArray_t *holdingRegisters);
00121 
00122 public:
00123     /**
00124      * Function to start the Modbus RTU Slave engine.
00125      */
00126     void trigger(void);
00127 
00128     /**
00129      * Gets the status of the internal FSM.
00130      * @return Status value as defined in MbStatusTypes_t.
00131      */
00132     MbStatusTypes_t  getStatus(void);
00133     
00134     /**
00135      * Internal FSM process.
00136      */    
00137     void FSM(void);
00138 
00139 private:
00140     /**
00141      * Handler for read holding registers function request.
00142      * @return Error or success code as defined in MbReceivedMessageErrors_t.
00143      */
00144     MbReceivedMessageErrors_t readHoldingRegistersHandler(void);
00145     
00146     /**
00147      * Handler for read coil registers function request.
00148      * @return Error or success code as defined in MbReceivedMessageErrors_t.
00149      */    
00150     MbReceivedMessageErrors_t readCoilRegistersHandler(void);
00151     
00152     /**
00153      * Builds response message.
00154      * @return Error or success code as defined in MbReceivedMessageErrors_t.
00155      */    
00156     MbReceivedMessageErrors_t buildResponse(void);
00157 
00158     /**
00159      * Function that computes the CRC of a Modbus message.
00160      * @param *data Pointer to the message data.
00161      * @param uint8_t Length of the message.
00162      * @return The CRC Code.
00163      */
00164     uint16_t getCRC(uint8_t *  data,uint8_t len);
00165 
00166     /**
00167      * Verifies the CRC value of a message to determine it has been received correctly.
00168      * @param *data Pointer to the message data.
00169      * @return Returns 1 if the message has been well received, 0 otherwise.
00170      */
00171     uint8_t checkMessageCRC(uint8_t *  data);
00172 
00173     /**
00174      * Function that appends the header and tail bytes for a response message.
00175      * @return void.
00176      */
00177     void appendHeaderAndTailToMessage(void);
00178 
00179     /**
00180      * Function that checks for error in the received message.
00181      * @param *array Safe array being processed depending on the modbus function.
00182      * @return The error or success code as defined in MbReceivedMessageErrors_t.
00183      */
00184     MbReceivedMessageErrors_t checkReceivedMessageErrors(ThreadSafeArray_t *array);
00185 
00186 private:
00187     /** Internal state of the modbus FSM.
00188      */
00189     MbSlaveRTUStates_t m_state;
00190     
00191     /** Response frame.
00192      */    
00193     MbSlaveRTUFrame_t m_frame;
00194     
00195     /** Modbus address.
00196      */
00197     uint8_t m_address;
00198     
00199     /** Modbus process status.
00200      */
00201     MbStatusTypes_t  m_status;
00202     
00203     /** Memory map for registers.
00204      */
00205     MemoryMap_t m_memoryMap;
00206     
00207     /** Queue to write response data.
00208      */
00209     MessageQueue<uint8_t>* m_bTxQueue;
00210     
00211     /** Queue to read incomming requests from.
00212      */
00213     MessageQueue<uint8_t>* m_bRxQueue;
00214     
00215     /** Internal byte array to copy incomming requests.
00216      */
00217     uint8_t m_receivedMessage[MODBUS_MAX_LEN];
00218     
00219     /** Internal byte array to generate responses.
00220      */   
00221     uint8_t m_responseMessage[MODBUS_MAX_LEN];
00222 };
00223 #endif