Gabriel Rivas / ModbusSlaveRTU

Dependents:   Nucleo_modbus_protocol_test

ModbusSlaveRTU.h

Committer:
gabrielrivas
Date:
2015-01-19
Revision:
0:81fee41d95f1
Child:
1:5efaa10b9a3f

File content as of revision 0:81fee41d95f1:

#ifndef _MODBUS_SLAVE_RTU_H_
#define _MODBUS_SLAVE_RTU_H_

#include "mbed.h"
#include "rtos.h"
#include "MessageQueue.h"

#define MODBUS_MAX_LEN (256)

struct ThreadSafeArray_t {
    Mutex mutex;
    uint8_t *data;
    uint32_t length;
};

class ModbusSlaveRTU
{
public:
    /*! Modbus response message bytes indexes. */
    enum MbResponseByteIndex_t {
        ADDRESS    = 0,
        FUNCTION   = 1,
        BYTE_COUNT = 2,
        DATA_START = 3
    };

    /*! Modbus errors reported during message processing. */
    enum MbReceivedMessageErrors_t {
        ADDRESS_ERROR    = 0x10,
        CRC_ERROR        = 0x11,
        OFFSET_ERROR     = 0x12,
        BYTE_COUNT_ERROR = 0x13
    };

    enum MbStatusTypes_t {
        MESSAGE_LISTENING  = 0x20,
        MESSAGE_PROCESSING = 0x21,
        MESSAGE_SENDING    = 0x23
    };

    enum MbSlaveRTUStates_t {
        WAIT_REQUEST_MESSAGE      = 0x00,
        GET_RECEIVED_BYTES        = 0x01,
        BUILD_RESPONSE_MESSAGE    = 0x02,
        TRANSMIT_RESPONSE_MESSAGE = 0x03
    };

    /*! Modbus function codes. */
    enum MbFunctionCodes_t {
        READ_COIL_STATUS        = 0x01, /**< Function to read a single coil status.*/
        READ_INPUT_STATUS       = 0x02, /**< Function to read input register.*/
        READ_HOLDING_REGISTERS  = 0x03, /**< Function to read one or more internal holding resgisters.*/
        READ_INPUT_REGISTERS    = 0x04, /**< Function to read one or more input resgisters.*/
        FORCE_SINGLE_COIL       = 0x05, /**< Function to write a value into a single discrete output.*/
        PRESET_SINGLE_REGISTER  = 0x06, /**< Function to write a value into a single holding register.*/
        READ_EXCEPTION_STATUS   = 0x07, /**< Function to request the value of the status byte.*/
        LOOPBACK_TEST           = 0x08, /**< Function to test the communications interface. Returns the same message.*/
        FORCE_MULTIPLE_COILS    = 0x0F  /**< Function to set more than one coil to a given value*/
    };

    /*! Modbus frame structure elements. */
    struct MbSlaveRTUFrame_t {
        uint8_t mAddress;             /**< Slave device address.*/
        MbFunctionCodes_t mFunction;  /**< Requested function of type MbFunctionCodes_t.*/
        uint16_t mOffset;             /**< Offset in bytes from the starting address.*/
        uint16_t mByteCount;
        uint8_t mCRCH;
        uint8_t  mCRCL;
        uint16_t mSize;
    };

    struct MemoryMap_t {
        ThreadSafeArray_t *coilRegisters;
        ThreadSafeArray_t *holdingRegisters;
        ThreadSafeArray_t *inputRegisters;
    };

    typedef struct MbSlaveRTUControl {
        uint8_t MbAddress;
        uint8_t rxByte;
        uint32_t receiveIndex;
        MbStatusTypes_t status;
    } MbSlaveRTUControl_t;


public:
    /**
     * @brief Initialization function for the Modbus RTU Slave.
     * @param id.
     * @param *coilRegisters Pointer to the memory space reserved for the coil registers.
     * @param *inputRegisters Pointer to the memory space reserved for the input registers.
     * @param *inputRegisters Pointer to the memory space reserved for the holding registers.
     * @return void
     */
    ModbusSlaveRTU( uint8_t id,
                    MessageQueue<uint8_t>* txQueue,
                    MessageQueue<uint8_t>* rxQueue,
                    ThreadSafeArray_t *coilRegisters,
                    ThreadSafeArray_t *inputRegisters,
                    ThreadSafeArray_t *holdingRegisters);

public:
    /**
     * @brief Function to start the Modbus RTU Slave engine.
     * @return void
     */
    void trigger(void);

    /**
     * @brief Function to start the Modbus RTU Slave engine.
     * @return MbStatusTypes_t
     */
    MbStatusTypes_t getStatus(void);
    void FSM(void);

private:
    uint8_t readHoldingRegistersHandler(void);
    uint8_t readCoilRegistersHandler(void);
    uint8_t buildResponse(void);

    /**
     * @brief Function that computes the CRC of a Modbus message.
     * @param *data Pointer to the message data.
     * @param uint8_t Length of the message.
     * @return The CRC Code.
     */
    uint16_t getCRC(uint8_t *  data,uint8_t len);

    /**
     * @brief Verifies the CRC value of a message to determine it has been received correctly.
     * @param *data Pointer to the message data.
     * @return Returns 1 if the message has been well received, 0 otherwise.
     */
    uint8_t checkMessageCRC(uint8_t *  data);

    /**
     * @brief Function that appends the header and tail bytes for a response message.
     * @return void.
     */
    void appendHeaderAndTailToMessage(void);

    /**
     * @brief Function that checks for error in the received message.
     * @param *array Safe array being processed depending on the modbus function.
     * @return uint8_t the error or success code.
     */
    uint8_t checkReceivedMessageErrors(ThreadSafeArray_t *array);

private:
    MbSlaveRTUStates_t m_state;
    MbSlaveRTUFrame_t m_frame;
    MbSlaveRTUControl_t m_control;
    MemoryMap_t m_memoryMap;
    MessageQueue<uint8_t>* m_bTxQueue;
    MessageQueue<uint8_t>* m_bRxQueue;
    uint8_t m_receivedMessage[MODBUS_MAX_LEN];
    uint8_t m_responseMessage[MODBUS_MAX_LEN];
};
#endif