/***************************************************************************//**
 *   @file   MODBUSTCPServer.c
 *   @brief  MODBUS TCP Serveur Application
 *   @author Kévin MARCHAND(Kevin.marchand@intelligence-electronique.com)
********************************************************************************
 * Copyright 2014(c) PLCD, Inc.
 *
 * Implémente un serveur MODBUS TCP sur le port 502
 *
 * - Cette exemple peut être adapté pour effectuer d'autres opérations.
 *
********************************************************************************
 *   SVN Revision: 1
*******************************************************************************/

/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/

#define __MODBUSTCPSERVER_C

#include "TCPIPStack/TCPIPConfig.h"

#if defined(STACK_USE_MODBUS_TCP_SERVER)

#include "Include/TCPIPStack/TCPIP.h"
#include "MODBUSTCPServer.h"

/******************************************************************************/
/************************ Variables Declarations ******************************/
/******************************************************************************/
_MODBUS_COMMAND MODBUS_COMMAND;

char ReadByteReverse = 1;           //If a modbus client requires to reverse the byte order for HOLDING REGISTER
char InputByteReverse = 1;
char WriteByteReverse = 0;

static BYTE iLlegal_Function;
BYTE MODBUS_RX[MODBUS_RX_BUFFER_SIZE];          //MODBUS TCP buffer
BYTE MODBUS_TX[MODBUS_TX_BUFFER_SIZE];          //Buffer to transfer MODBUS response
WORD_VAL1 COIL;
BYTE COIL_REG[COIL_SIZE];                       //Saves addresses and value for coils

WORD HOLDING_REG[HOLDING_REG_SIZE] =
                        {
                        0x0000,     //0
                        0x0001,     //1
                        0x0002,     //2
                        0x0003,     //3
                        0x0004,     //4
                        0x0005,     //5
                        0x0006,     //6
                        0x0007,     //7
                        0x0008,     //8
                        0x0009,     //9
                        0x0009,     //10
                        0x0008,     //11
                        0x0007,     //12
                        0x0007,     //13
                        0x0006,     //14
                        0x0005,     //15
                        0x0004,     //16
                        0x0003,     //17
                        0x0002,     //18
                        0x0001,     //19
                        0x0025,     //20
                        0x0035,     //21
                        0x0036,     //22
                        0x9957,     //23
                        0x7890      //24
                       };

    // Copy potentiometer and temperature sensor results in to Input register
WORD    INPUT_REG[INPUT_REG_SIZE] =
                        {
                        0x0001,     //0
                        0x0000,     //1
                        0x0000,     //2
                        0x0003,     //3
                        0x0004,     //4
                        0x0005,     //5
                        0x0006,     //6
                        0x0007,     //7
                        0x0008,     //8
                        0x0009,     //9
                        0x0009,     //10
                        0x0000,     //11
                        0x0000,     //12
                        0x0007,     //13
                        0x0006,     //14
                        0x0005,     //15
                        0x0004,     //16
                        0x0003,     //17
                        0x0002,     //18
                        0x0001      //19
                        };

/***************************************************************************//**
 * @brief Implements a MODBUS_RX TCP Server.
 * @pre La stack TCPIP doit être initialisée.
 * @param none.
 * @return none.
*******************************************************************************/
int MODBUSTCPServer(void)
{
int                 w;
int                 wMaxGet;

ProcessReceivedMessage();

switch (MODBUS_COMMAND.FunctionCode)
{
    case ReadHoldingRegister:
    case ReadInputRegister:
        //Assemble the data
        LectureMots(5, 0);

        //Test if server sends Exception error to the client
        if (!(MODBUS_TX[MODBUS_FunctionCode] == 0X83))
            w = 0x09 + MODBUS_TX[8];
        else w = 9;

        return(w);
        break;

    case WriteMultipleRegister:
        //Assemble the data
        EcritureMots(5);

        //Test if server sends Exception error to the client
        if (!(MODBUS_TX[MODBUS_FunctionCode] == 0X90))
            w = 12;
        else w = 9;

        return(w);
        break;

    case WriteSingleRegister:
        //Assemble the data
//      EcritureMots();

        //Test if server sends Exception error to the client
        if (!(MODBUS_TX[MODBUS_FunctionCode] == 0X85))
            w = 0x09 + MODBUS_TX[8];
        else w = 12;

        return(w);
        break;
}
}

#endif //#if defined(STACK_USE_MODBUS_TCP_SERVER)


/***************************************************************************//**
 * @brief Decodes Modbus commands. Also, tests if this server supports the requested Modbus command
 * @param none.
 * @return none.
*******************************************************************************/
void ProcessReceivedMessage(void)
{
    //Transaction Identifier
    MODBUS_COMMAND.TransactionID.v[1] = MODBUS_RX[0];
    MODBUS_COMMAND.TransactionID.v[0] = MODBUS_RX[1];
    //Protocol Identifier
    MODBUS_COMMAND.ProtocolID.v[1] = MODBUS_RX[2];
    MODBUS_COMMAND.ProtocolID.v[0] = MODBUS_RX[3];
    //Number of bytes to receive
    MODBUS_COMMAND.Length = MODBUS_RX[5];
    //Unit Identifier
    MODBUS_COMMAND.UnitID = MODBUS_RX[6];
    //Function code
    MODBUS_COMMAND.FunctionCode = MODBUS_RX[7];
    //Address
    MODBUS_COMMAND.StartAddress.v[1] = MODBUS_RX[8];
    MODBUS_COMMAND.StartAddress.v[0] = MODBUS_RX[9];
    //Number of Register or Quantity
    MODBUS_COMMAND.NumberOfRegister.v[1] = MODBUS_RX[10];
    MODBUS_COMMAND.NumberOfRegister.v[0] = MODBUS_RX[11];

     //Verify the function code
    if(!((MODBUS_COMMAND.FunctionCode == ReadHoldingRegister)      ||
            (MODBUS_COMMAND.FunctionCode == WriteMultipleRegister) ||
            (MODBUS_COMMAND.FunctionCode == ReadInputRegister)     ||
            (MODBUS_COMMAND.FunctionCode == WriteSingleRegister)))
    {
        ModbusError(Illegal_Function_Code);
        memcpy(MODBUS_TX, MODBUS_RX, 9);
        iLlegal_Function = 1;
        return;
    }
}


/***************************************************************************//**
 * @brief Implements Modbus error command.
 * Reply with Modbus error code value.
 * @param ExceptionCode - error code value.
 * @return none.
*******************************************************************************/
void ModbusError(unsigned char ExceptionCode)
{

    MODBUS_RX[4]=0X00;
    MODBUS_RX[5]=0X03;
    MODBUS_RX[MODBUS_FunctionCode]+=0X80;
    MODBUS_RX[MODBUS_ExceptionCode]=ExceptionCode;

     //Copy MODBUS_RX into MODBUS_TX and send MODBUS_TX as response
    memcpy(MODBUS_TX, MODBUS_RX, 9);

}



