Port of the FreeModbus Libary for mbed

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
cam
Date:
Thu Apr 15 12:10:34 2010 +0000
Commit message:

Changed in this revision

main.cpp Show annotated file Show diff for this revision Revisions of this file
mb.cpp Show annotated file Show diff for this revision Revisions of this file
mb.h Show annotated file Show diff for this revision Revisions of this file
mbconfig.h Show annotated file Show diff for this revision Revisions of this file
mbcrc.cpp Show annotated file Show diff for this revision Revisions of this file
mbcrc.h Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
mbframe.h Show annotated file Show diff for this revision Revisions of this file
mbfunc.h Show annotated file Show diff for this revision Revisions of this file
mbfunccoils.cpp Show annotated file Show diff for this revision Revisions of this file
mbfuncdiag.cpp Show annotated file Show diff for this revision Revisions of this file
mbfuncdisc.cpp Show annotated file Show diff for this revision Revisions of this file
mbfuncholding.cpp Show annotated file Show diff for this revision Revisions of this file
mbfuncinput.cpp Show annotated file Show diff for this revision Revisions of this file
mbfuncother.cpp Show annotated file Show diff for this revision Revisions of this file
mbport.h Show annotated file Show diff for this revision Revisions of this file
mbproto.h Show annotated file Show diff for this revision Revisions of this file
mbrtu.cpp Show annotated file Show diff for this revision Revisions of this file
mbrtu.h Show annotated file Show diff for this revision Revisions of this file
mbutils.cpp Show annotated file Show diff for this revision Revisions of this file
mbutils.h Show annotated file Show diff for this revision Revisions of this file
port.h Show annotated file Show diff for this revision Revisions of this file
portevent.cpp Show annotated file Show diff for this revision Revisions of this file
portserial.cpp Show annotated file Show diff for this revision Revisions of this file
porttimer.cpp Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Thu Apr 15 12:10:34 2010 +0000
@@ -0,0 +1,146 @@
+/*
+ * FreeModbus Libary: BARE Demo Application
+ * Copyright (C) 2006 Christian Walter <wolti@sil.at>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * File: $Id: demo.c,v 1.1 2006/08/22 21:35:13 wolti Exp $
+ */
+
+/* ----------------------- System includes --------------------------------*/
+
+/* ----------------------- Modbus includes ----------------------------------*/
+#include "mb.h"
+#include "mbport.h"
+
+/* ----------------------- Defines ------------------------------------------*/
+#define REG_INPUT_START 1000
+#define REG_INPUT_NREGS 4
+#define SLAVE_ID 0x0A
+
+/* ----------------------- Static variables ---------------------------------*/
+static USHORT   usRegInputStart = REG_INPUT_START;
+static USHORT   usRegInputBuf[REG_INPUT_NREGS];
+
+/* ----------------------- Start implementation -----------------------------*/
+int
+main( void )
+{
+    eMBErrorCode    eStatus;
+
+    eStatus = eMBInit( MB_RTU, SLAVE_ID, 0, 9600, MB_PAR_NONE );
+
+    /* Enable the Modbus Protocol Stack. */
+    eStatus = eMBEnable(  );
+    
+    // Initialise some registers
+    usRegInputBuf[1] = 0x1234;
+    usRegInputBuf[2] = 0x5678;
+    usRegInputBuf[3] = 0x9abc;        
+
+    for( ;; )
+    {
+        ( void )eMBPoll(  );
+                
+        /* Here we simply count the number of poll cycles. */
+        usRegInputBuf[0]++;
+    }
+}
+
+eMBErrorCode
+eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
+{
+    eMBErrorCode    eStatus = MB_ENOERR;
+    int             iRegIndex;
+
+    if( ( usAddress >= REG_INPUT_START )
+        && ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
+    {
+        iRegIndex = ( int )( usAddress - usRegInputStart );
+        while( usNRegs > 0 )
+        {
+            *pucRegBuffer++ =
+                ( unsigned char )( usRegInputBuf[iRegIndex] >> 8 );
+            *pucRegBuffer++ =
+                ( unsigned char )( usRegInputBuf[iRegIndex] & 0xFF );
+            iRegIndex++;
+            usNRegs--;
+        }
+    }
+    else
+    {
+        eStatus = MB_ENOREG;
+    }
+
+    return eStatus;
+}
+
+eMBErrorCode
+eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
+{
+    eMBErrorCode    eStatus = MB_ENOERR;
+    int             iRegIndex;
+
+    if (eMode == MB_REG_READ)
+    {
+        if( ( usAddress >= REG_INPUT_START )
+            && ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
+        {
+            iRegIndex = ( int )( usAddress - usRegInputStart );
+            while( usNRegs > 0 )
+            {
+                *pucRegBuffer++ =
+                    ( unsigned char )( usRegInputBuf[iRegIndex] >> 8 );
+                *pucRegBuffer++ =
+                    ( unsigned char )( usRegInputBuf[iRegIndex] & 0xFF );
+                iRegIndex++;
+                usNRegs--;
+            }
+        }
+    }
+
+    if (eMode == MB_REG_WRITE)
+    {
+        if( ( usAddress >= REG_INPUT_START )
+            && ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
+        {
+            iRegIndex = ( int )( usAddress - usRegInputStart );
+            while( usNRegs > 0 )
+            {
+                usRegInputBuf[iRegIndex] =  ((unsigned int) *pucRegBuffer << 8) | ((unsigned int) *(pucRegBuffer+1));
+                pucRegBuffer+=2;
+                iRegIndex++;
+                usNRegs--;
+            }
+        }
+    }
+
+    return eStatus;
+}
+
+
+eMBErrorCode
+eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils,
+               eMBRegisterMode eMode )
+{
+    return MB_ENOREG;
+}
+
+eMBErrorCode
+eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
+{
+    return MB_ENOREG;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mb.cpp	Thu Apr 15 12:10:34 2010 +0000
@@ -0,0 +1,357 @@
+/*
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * File: $Id: mb.c,v 1.27 2007/02/18 23:45:41 wolti Exp $
+ */
+
+/* ----------------------- System includes ----------------------------------*/
+#include "stdlib.h"
+#include "string.h"
+
+/* ----------------------- Platform includes --------------------------------*/
+#include "port.h"
+
+/* ----------------------- Modbus includes ----------------------------------*/
+#include "mb.h"
+#include "mbconfig.h"
+#include "mbframe.h"
+#include "mbproto.h"
+#include "mbfunc.h"
+#include "mbport.h"
+#if MB_RTU_ENABLED == 1
+#include "mbrtu.h"
+#endif
+#if MB_ASCII_ENABLED == 1
+#include "mbascii.h"
+#endif
+#if MB_TCP_ENABLED == 1
+#include "mbtcp.h"
+#endif
+
+#ifndef MB_PORT_HAS_CLOSE
+#define MB_PORT_HAS_CLOSE 0
+#endif
+
+/* ----------------------- Static variables ---------------------------------*/
+
+
+static UCHAR    ucMBAddress;
+static eMBMode  eMBCurrentMode;
+
+static enum {
+    STATE_ENABLED,
+    STATE_DISABLED,
+    STATE_NOT_INITIALIZED
+} eMBState = STATE_NOT_INITIALIZED;
+
+/* Functions pointer which are initialized in eMBInit( ). Depending on the
+ * mode (RTU or ASCII) the are set to the correct implementations.
+ */
+static peMBFrameSend peMBFrameSendCur;
+static pvMBFrameStart pvMBFrameStartCur;
+static pvMBFrameStop pvMBFrameStopCur;
+static peMBFrameReceive peMBFrameReceiveCur;
+static pvMBFrameClose pvMBFrameCloseCur;
+
+/* Callback functions required by the porting layer. They are called when
+ * an external event has happend which includes a timeout or the reception
+ * or transmission of a character.
+ */
+BOOL( *pxMBFrameCBByteReceived ) ( void );
+BOOL( *pxMBFrameCBTransmitterEmpty ) ( void );
+BOOL( *pxMBPortCBTimerExpired ) ( void );
+
+BOOL( *pxMBFrameCBReceiveFSMCur ) ( void );
+BOOL( *pxMBFrameCBTransmitFSMCur ) ( void );
+
+/* An array of Modbus functions handlers which associates Modbus function
+ * codes with implementing functions.
+ */
+static xMBFunctionHandler xFuncHandlers[MB_FUNC_HANDLERS_MAX] = {
+#if MB_FUNC_OTHER_REP_SLAVEID_ENABLED > 0
+    {MB_FUNC_OTHER_REPORT_SLAVEID, eMBFuncReportSlaveID},
+#endif
+#if MB_FUNC_READ_INPUT_ENABLED > 0
+    {MB_FUNC_READ_INPUT_REGISTER, eMBFuncReadInputRegister},
+#endif
+#if MB_FUNC_READ_HOLDING_ENABLED > 0
+    {MB_FUNC_READ_HOLDING_REGISTER, eMBFuncReadHoldingRegister},
+#endif
+#if MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED > 0
+    {MB_FUNC_WRITE_MULTIPLE_REGISTERS, eMBFuncWriteMultipleHoldingRegister},
+#endif
+#if MB_FUNC_WRITE_HOLDING_ENABLED > 0
+    {MB_FUNC_WRITE_REGISTER, eMBFuncWriteHoldingRegister},
+#endif
+#if MB_FUNC_READWRITE_HOLDING_ENABLED > 0
+    {MB_FUNC_READWRITE_MULTIPLE_REGISTERS, eMBFuncReadWriteMultipleHoldingRegister},
+#endif
+#if MB_FUNC_READ_COILS_ENABLED > 0
+    {MB_FUNC_READ_COILS, eMBFuncReadCoils},
+#endif
+#if MB_FUNC_WRITE_COIL_ENABLED > 0
+    {MB_FUNC_WRITE_SINGLE_COIL, eMBFuncWriteCoil},
+#endif
+#if MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED > 0
+    {MB_FUNC_WRITE_MULTIPLE_COILS, eMBFuncWriteMultipleCoils},
+#endif
+#if MB_FUNC_READ_DISCRETE_INPUTS_ENABLED > 0
+    {MB_FUNC_READ_DISCRETE_INPUTS, eMBFuncReadDiscreteInputs},
+#endif
+};
+
+/* ----------------------- Start implementation -----------------------------*/
+eMBErrorCode
+eMBInit( eMBMode eMode, UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity ) {
+    eMBErrorCode    eStatus = MB_ENOERR;
+
+    /* check preconditions */
+    if ( ( ucSlaveAddress == MB_ADDRESS_BROADCAST ) ||
+            ( ucSlaveAddress < MB_ADDRESS_MIN ) || ( ucSlaveAddress > MB_ADDRESS_MAX ) ) {
+        eStatus = MB_EINVAL;
+    } else {
+        ucMBAddress = ucSlaveAddress;
+
+        switch ( eMode ) {
+#if MB_RTU_ENABLED > 0
+            case MB_RTU:
+                pvMBFrameStartCur = eMBRTUStart;
+                pvMBFrameStopCur = eMBRTUStop;
+                peMBFrameSendCur = eMBRTUSend;
+                peMBFrameReceiveCur = eMBRTUReceive;
+                pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBPortClose : NULL;
+                pxMBFrameCBByteReceived = xMBRTUReceiveFSM;
+                pxMBFrameCBTransmitterEmpty = xMBRTUTransmitFSM;
+                pxMBPortCBTimerExpired = xMBRTUTimerT35Expired;
+
+                eStatus = eMBRTUInit( ucMBAddress, ucPort, ulBaudRate, eParity );
+                break;
+#endif
+#if MB_ASCII_ENABLED > 0
+            case MB_ASCII:
+                pvMBFrameStartCur = eMBASCIIStart;
+                pvMBFrameStopCur = eMBASCIIStop;
+                peMBFrameSendCur = eMBASCIISend;
+                peMBFrameReceiveCur = eMBASCIIReceive;
+                pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBPortClose : NULL;
+                pxMBFrameCBByteReceived = xMBASCIIReceiveFSM;
+                pxMBFrameCBTransmitterEmpty = xMBASCIITransmitFSM;
+                pxMBPortCBTimerExpired = xMBASCIITimerT1SExpired;
+
+                eStatus = eMBASCIIInit( ucMBAddress, ucPort, ulBaudRate, eParity );
+                break;
+#endif
+            default:
+                eStatus = MB_EINVAL;
+        }
+
+        if ( eStatus == MB_ENOERR ) {
+            if ( !xMBPortEventInit(  ) ) {
+                /* port dependent event module initalization failed. */
+                eStatus = MB_EPORTERR;
+            } else {
+                eMBCurrentMode = eMode;
+                eMBState = STATE_DISABLED;
+            }
+        }
+    }
+    return eStatus;
+}
+
+#if MB_TCP_ENABLED > 0
+eMBErrorCode
+eMBTCPInit( USHORT ucTCPPort ) {
+    eMBErrorCode    eStatus = MB_ENOERR;
+
+    if ( ( eStatus = eMBTCPDoInit( ucTCPPort ) ) != MB_ENOERR ) {
+        eMBState = STATE_DISABLED;
+    } else if ( !xMBPortEventInit(  ) ) {
+        /* Port dependent event module initalization failed. */
+        eStatus = MB_EPORTERR;
+    } else {
+        pvMBFrameStartCur = eMBTCPStart;
+        pvMBFrameStopCur = eMBTCPStop;
+        peMBFrameReceiveCur = eMBTCPReceive;
+        peMBFrameSendCur = eMBTCPSend;
+        pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBTCPPortClose : NULL;
+        ucMBAddress = MB_TCP_PSEUDO_ADDRESS;
+        eMBCurrentMode = MB_TCP;
+        eMBState = STATE_DISABLED;
+    }
+    return eStatus;
+}
+#endif
+
+
+eMBErrorCode
+eMBRegisterCB( UCHAR ucFunctionCode, pxMBFunctionHandler pxHandler ) {
+    int             i;
+    eMBErrorCode    eStatus;
+
+    if ( ( 0 < ucFunctionCode ) && ( ucFunctionCode <= 127 ) ) {
+        ENTER_CRITICAL_SECTION(  );
+        if ( pxHandler != NULL ) {
+            for ( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ ) {
+                if ( ( xFuncHandlers[i].pxHandler == NULL ) ||
+                        ( xFuncHandlers[i].pxHandler == pxHandler ) ) {
+                    xFuncHandlers[i].ucFunctionCode = ucFunctionCode;
+                    xFuncHandlers[i].pxHandler = pxHandler;
+                    break;
+                }
+            }
+            eStatus = ( i != MB_FUNC_HANDLERS_MAX ) ? MB_ENOERR : MB_ENORES;
+        } else {
+            for ( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ ) {
+                if ( xFuncHandlers[i].ucFunctionCode == ucFunctionCode ) {
+                    xFuncHandlers[i].ucFunctionCode = 0;
+                    xFuncHandlers[i].pxHandler = NULL;
+                    break;
+                }
+            }
+            /* Remove can't fail. */
+            eStatus = MB_ENOERR;
+        }
+        EXIT_CRITICAL_SECTION(  );
+    } else {
+        eStatus = MB_EINVAL;
+    }
+    return eStatus;
+}
+
+
+eMBErrorCode
+eMBClose( void ) {
+    eMBErrorCode    eStatus = MB_ENOERR;
+
+    if ( eMBState == STATE_DISABLED ) {
+        if ( pvMBFrameCloseCur != NULL ) {
+            pvMBFrameCloseCur(  );
+        }
+    } else {
+        eStatus = MB_EILLSTATE;
+    }
+    return eStatus;
+}
+
+eMBErrorCode
+eMBEnable( void ) {
+    eMBErrorCode    eStatus = MB_ENOERR;
+
+    if ( eMBState == STATE_DISABLED ) {
+        /* Activate the protocol stack. */
+        pvMBFrameStartCur(  );
+        eMBState = STATE_ENABLED;
+    } else {
+        eStatus = MB_EILLSTATE;
+    }
+    return eStatus;
+}
+
+eMBErrorCode
+eMBDisable( void ) {
+    eMBErrorCode    eStatus;
+
+    if ( eMBState == STATE_ENABLED ) {
+        pvMBFrameStopCur(  );
+        eMBState = STATE_DISABLED;
+        eStatus = MB_ENOERR;
+    } else if ( eMBState == STATE_DISABLED ) {
+        eStatus = MB_ENOERR;
+    } else {
+        eStatus = MB_EILLSTATE;
+    }
+    return eStatus;
+}
+
+eMBErrorCode
+eMBPoll( void ) {
+    static UCHAR   *ucMBFrame;
+    static UCHAR    ucRcvAddress;
+    static UCHAR    ucFunctionCode;
+    static USHORT   usLength;
+    static eMBException eException;
+
+    int             i;
+    eMBErrorCode    eStatus = MB_ENOERR;
+    eMBEventType    eEvent;
+
+    /* Check if the protocol stack is ready. */
+    if ( eMBState != STATE_ENABLED ) {
+        return MB_EILLSTATE;
+    }
+
+    /* Check if there is a event available. If not return control to caller.
+     * Otherwise we will handle the event. */
+    if ( xMBPortEventGet( &eEvent ) == TRUE ) {
+        switch ( eEvent ) {
+            case EV_READY:
+                break;
+
+            case EV_FRAME_RECEIVED:
+                eStatus = peMBFrameReceiveCur( &ucRcvAddress, &ucMBFrame, &usLength );
+                if ( eStatus == MB_ENOERR ) {
+                    /* Check if the frame is for us. If not ignore the frame. */
+                    if ( ( ucRcvAddress == ucMBAddress ) || ( ucRcvAddress == MB_ADDRESS_BROADCAST ) ) {
+                        ( void )xMBPortEventPost( EV_EXECUTE );
+                    }
+                }
+                break;
+
+            case EV_EXECUTE:
+                ucFunctionCode = ucMBFrame[MB_PDU_FUNC_OFF];
+                eException = MB_EX_ILLEGAL_FUNCTION;
+                
+ 
+                for ( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ ) {
+                    /* No more function handlers registered. Abort. */
+                    if ( xFuncHandlers[i].ucFunctionCode == 0 ) {
+                        break;
+                    } else if ( xFuncHandlers[i].ucFunctionCode == ucFunctionCode ) {
+                        eException = xFuncHandlers[i].pxHandler( ucMBFrame, &usLength );
+                        break;
+                    }
+                }
+
+                /* If the request was not sent to the broadcast address we
+                 * return a reply. */
+                if ( ucRcvAddress != MB_ADDRESS_BROADCAST ) {
+                    if ( eException != MB_EX_NONE ) {
+                        /* An exception occured. Build an error frame. */
+                        usLength = 0;
+                        ucMBFrame[usLength++] = ( UCHAR )( ucFunctionCode | MB_FUNC_ERROR );
+                        ucMBFrame[usLength++] = eException;
+                    }
+                    eStatus = peMBFrameSendCur( ucMBAddress, ucMBFrame, usLength );
+                }
+                break;
+
+            case EV_FRAME_SENT:
+                break;
+        }
+    }
+    return MB_ENOERR;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mb.h	Thu Apr 15 12:10:34 2010 +0000
@@ -0,0 +1,417 @@
+/* 
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * File: $Id: mb.h,v 1.17 2006/12/07 22:10:34 wolti Exp $
+ */
+
+#ifndef _MB_H
+#define _MB_H
+
+#include "port.h"
+
+#ifdef __cplusplus
+PR_BEGIN_EXTERN_C
+#endif
+
+#include "mbport.h"
+#include "mbproto.h"
+
+/*! \defgroup modbus Modbus
+ * \code #include "mb.h" \endcode
+ *
+ * This module defines the interface for the application. It contains
+ * the basic functions and types required to use the Modbus protocol stack.
+ * A typical application will want to call eMBInit() first. If the device
+ * is ready to answer network requests it must then call eMBEnable() to activate
+ * the protocol stack. In the main loop the function eMBPoll() must be called
+ * periodically. The time interval between pooling depends on the configured
+ * Modbus timeout. If an RTOS is available a separate task should be created
+ * and the task should always call the function eMBPoll().
+ *
+ * \code
+ * // Initialize protocol stack in RTU mode for a slave with address 10 = 0x0A
+ * eMBInit( MB_RTU, 0x0A, 38400, MB_PAR_EVEN );
+ * // Enable the Modbus Protocol Stack.
+ * eMBEnable(  );
+ * for( ;; )
+ * {
+ *     // Call the main polling loop of the Modbus protocol stack.
+ *     eMBPoll(  );
+ *     ...
+ * }
+ * \endcode
+ */
+
+/* ----------------------- Defines ------------------------------------------*/
+
+/*! \ingroup modbus
+ * \brief Use the default Modbus TCP port (502)
+ */
+#define MB_TCP_PORT_USE_DEFAULT 0   
+
+/* ----------------------- Type definitions ---------------------------------*/
+
+/*! \ingroup modbus
+ * \brief Modbus serial transmission modes (RTU/ASCII).
+ *
+ * Modbus serial supports two transmission modes. Either ASCII or RTU. RTU
+ * is faster but has more hardware requirements and requires a network with
+ * a low jitter. ASCII is slower and more reliable on slower links (E.g. modems)
+ */
+    typedef enum
+{
+    MB_RTU,                     /*!< RTU transmission mode. */
+    MB_ASCII,                   /*!< ASCII transmission mode. */
+    MB_TCP                      /*!< TCP mode. */
+} eMBMode;
+
+/*! \ingroup modbus
+ * \brief If register should be written or read.
+ *
+ * This value is passed to the callback functions which support either
+ * reading or writing register values. Writing means that the application
+ * registers should be updated and reading means that the modbus protocol
+ * stack needs to know the current register values.
+ *
+ * \see eMBRegHoldingCB( ), eMBRegCoilsCB( ), eMBRegDiscreteCB( ) and 
+ *   eMBRegInputCB( ).
+ */
+typedef enum
+{
+    MB_REG_READ,                /*!< Read register values and pass to protocol stack. */
+    MB_REG_WRITE                /*!< Update register values. */
+} eMBRegisterMode;
+
+/*! \ingroup modbus
+ * \brief Errorcodes used by all function in the protocol stack.
+ */
+typedef enum
+{
+    MB_ENOERR,                  /*!< no error. */
+    MB_ENOREG,                  /*!< illegal register address. */
+    MB_EINVAL,                  /*!< illegal argument. */
+    MB_EPORTERR,                /*!< porting layer error. */
+    MB_ENORES,                  /*!< insufficient resources. */
+    MB_EIO,                     /*!< I/O error. */
+    MB_EILLSTATE,               /*!< protocol stack in illegal state. */
+    MB_ETIMEDOUT                /*!< timeout error occurred. */
+} eMBErrorCode;
+
+
+/* ----------------------- Function prototypes ------------------------------*/
+/*! \ingroup modbus
+ * \brief Initialize the Modbus protocol stack.
+ *
+ * This functions initializes the ASCII or RTU module and calls the
+ * init functions of the porting layer to prepare the hardware. Please
+ * note that the receiver is still disabled and no Modbus frames are
+ * processed until eMBEnable( ) has been called.
+ *
+ * \param eMode If ASCII or RTU mode should be used.
+ * \param ucSlaveAddress The slave address. Only frames sent to this
+ *   address or to the broadcast address are processed.
+ * \param ucPort The port to use. E.g. 1 for COM1 on windows. This value
+ *   is platform dependent and some ports simply choose to ignore it.
+ * \param ulBaudRate The baudrate. E.g. 19200. Supported baudrates depend
+ *   on the porting layer.
+ * \param eParity Parity used for serial transmission.
+ *
+ * \return If no error occurs the function returns eMBErrorCode::MB_ENOERR.
+ *   The protocol is then in the disabled state and ready for activation
+ *   by calling eMBEnable( ). Otherwise one of the following error codes 
+ *   is returned:
+ *    - eMBErrorCode::MB_EINVAL If the slave address was not valid. Valid
+ *        slave addresses are in the range 1 - 247.
+ *    - eMBErrorCode::MB_EPORTERR IF the porting layer returned an error.
+ */
+eMBErrorCode    eMBInit( eMBMode eMode, UCHAR ucSlaveAddress,
+                         UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity );
+
+/*! \ingroup modbus
+ * \brief Initialize the Modbus protocol stack for Modbus TCP.
+ *
+ * This function initializes the Modbus TCP Module. Please note that
+ * frame processing is still disabled until eMBEnable( ) is called.
+ *
+ * \param usTCPPort The TCP port to listen on.
+ * \return If the protocol stack has been initialized correctly the function
+ *   returns eMBErrorCode::MB_ENOERR. Otherwise one of the following error
+ *   codes is returned:
+ *    - eMBErrorCode::MB_EINVAL If the slave address was not valid. Valid
+ *        slave addresses are in the range 1 - 247.
+ *    - eMBErrorCode::MB_EPORTERR IF the porting layer returned an error.
+ */
+eMBErrorCode    eMBTCPInit( USHORT usTCPPort );
+
+/*! \ingroup modbus
+ * \brief Release resources used by the protocol stack.
+ *
+ * This function disables the Modbus protocol stack and release all
+ * hardware resources. It must only be called when the protocol stack 
+ * is disabled. 
+ *
+ * \note Note all ports implement this function. A port which wants to 
+ *   get an callback must define the macro MB_PORT_HAS_CLOSE to 1.
+ *
+ * \return If the resources where released it return eMBErrorCode::MB_ENOERR.
+ *   If the protocol stack is not in the disabled state it returns
+ *   eMBErrorCode::MB_EILLSTATE.
+ */
+eMBErrorCode    eMBClose( void );
+
+/*! \ingroup modbus
+ * \brief Enable the Modbus protocol stack.
+ *
+ * This function enables processing of Modbus frames. Enabling the protocol
+ * stack is only possible if it is in the disabled state.
+ *
+ * \return If the protocol stack is now in the state enabled it returns 
+ *   eMBErrorCode::MB_ENOERR. If it was not in the disabled state it 
+ *   return eMBErrorCode::MB_EILLSTATE.
+ */
+eMBErrorCode    eMBEnable( void );
+
+/*! \ingroup modbus
+ * \brief Disable the Modbus protocol stack.
+ *
+ * This function disables processing of Modbus frames.
+ *
+ * \return If the protocol stack has been disabled it returns 
+ *  eMBErrorCode::MB_ENOERR. If it was not in the enabled state it returns
+ *  eMBErrorCode::MB_EILLSTATE.
+ */
+eMBErrorCode    eMBDisable( void );
+
+/*! \ingroup modbus
+ * \brief The main pooling loop of the Modbus protocol stack.
+ *
+ * This function must be called periodically. The timer interval required
+ * is given by the application dependent Modbus slave timeout. Internally the
+ * function calls xMBPortEventGet() and waits for an event from the receiver or
+ * transmitter state machines. 
+ *
+ * \return If the protocol stack is not in the enabled state the function
+ *   returns eMBErrorCode::MB_EILLSTATE. Otherwise it returns 
+ *   eMBErrorCode::MB_ENOERR.
+ */
+eMBErrorCode    eMBPoll( void );
+
+/*! \ingroup modbus
+ * \brief Configure the slave id of the device.
+ *
+ * This function should be called when the Modbus function <em>Report Slave ID</em>
+ * is enabled ( By defining MB_FUNC_OTHER_REP_SLAVEID_ENABLED in mbconfig.h ).
+ *
+ * \param ucSlaveID Values is returned in the <em>Slave ID</em> byte of the
+ *   <em>Report Slave ID</em> response.
+ * \param xIsRunning If TRUE the <em>Run Indicator Status</em> byte is set to 0xFF.
+ *   otherwise the <em>Run Indicator Status</em> is 0x00.
+ * \param pucAdditional Values which should be returned in the <em>Additional</em>
+ *   bytes of the <em> Report Slave ID</em> response.
+ * \param usAdditionalLen Length of the buffer <code>pucAdditonal</code>.
+ *
+ * \return If the static buffer defined by MB_FUNC_OTHER_REP_SLAVEID_BUF in
+ *   mbconfig.h is to small it returns eMBErrorCode::MB_ENORES. Otherwise
+ *   it returns eMBErrorCode::MB_ENOERR.
+ */
+eMBErrorCode    eMBSetSlaveID( UCHAR ucSlaveID, BOOL xIsRunning,
+                               UCHAR const *pucAdditional,
+                               USHORT usAdditionalLen );
+
+/*! \ingroup modbus
+ * \brief Registers a callback handler for a given function code.
+ *
+ * This function registers a new callback handler for a given function code.
+ * The callback handler supplied is responsible for interpreting the Modbus PDU and
+ * the creation of an appropriate response. In case of an error it should return
+ * one of the possible Modbus exceptions which results in a Modbus exception frame
+ * sent by the protocol stack. 
+ *
+ * \param ucFunctionCode The Modbus function code for which this handler should
+ *   be registers. Valid function codes are in the range 1 to 127.
+ * \param pxHandler The function handler which should be called in case
+ *   such a frame is received. If \c NULL a previously registered function handler
+ *   for this function code is removed.
+ *
+ * \return eMBErrorCode::MB_ENOERR if the handler has been installed. If no
+ *   more resources are available it returns eMBErrorCode::MB_ENORES. In this
+ *   case the values in mbconfig.h should be adjusted. If the argument was not
+ *   valid it returns eMBErrorCode::MB_EINVAL.
+ */
+eMBErrorCode    eMBRegisterCB( UCHAR ucFunctionCode, 
+                               pxMBFunctionHandler pxHandler );
+
+/* ----------------------- Callback -----------------------------------------*/
+
+/*! \defgroup modbus_registers Modbus Registers
+ * \code #include "mb.h" \endcode
+ * The protocol stack does not internally allocate any memory for the
+ * registers. This makes the protocol stack very small and also usable on
+ * low end targets. In addition the values don't have to be in the memory
+ * and could for example be stored in a flash.<br>
+ * Whenever the protocol stack requires a value it calls one of the callback
+ * function with the register address and the number of registers to read
+ * as an argument. The application should then read the actual register values
+ * (for example the ADC voltage) and should store the result in the supplied
+ * buffer.<br>
+ * If the protocol stack wants to update a register value because a write
+ * register function was received a buffer with the new register values is
+ * passed to the callback function. The function should then use these values
+ * to update the application register values.
+ */
+
+/*! \ingroup modbus_registers
+ * \brief Callback function used if the value of a <em>Input Register</em>
+ *   is required by the protocol stack. The starting register address is given
+ *   by \c usAddress and the last register is given by <tt>usAddress +
+ *   usNRegs - 1</tt>.
+ *
+ * \param pucRegBuffer A buffer where the callback function should write
+ *   the current value of the modbus registers to.
+ * \param usAddress The starting address of the register. Input registers
+ *   are in the range 1 - 65535.
+ * \param usNRegs Number of registers the callback function must supply.
+ *
+ * \return The function must return one of the following error codes:
+ *   - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
+ *       Modbus response is sent.
+ *   - eMBErrorCode::MB_ENOREG If the application can not supply values
+ *       for registers within this range. In this case a 
+ *       <b>ILLEGAL DATA ADDRESS</b> exception frame is sent as a response.
+ *   - eMBErrorCode::MB_ETIMEDOUT If the requested register block is
+ *       currently not available and the application dependent response
+ *       timeout would be violated. In this case a <b>SLAVE DEVICE BUSY</b>
+ *       exception is sent as a response.
+ *   - eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case
+ *       a <b>SLAVE DEVICE FAILURE</b> exception is sent as a response.
+ */
+eMBErrorCode    eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress,
+                               USHORT usNRegs );
+
+/*! \ingroup modbus_registers
+ * \brief Callback function used if a <em>Holding Register</em> value is
+ *   read or written by the protocol stack. The starting register address
+ *   is given by \c usAddress and the last register is given by
+ *   <tt>usAddress + usNRegs - 1</tt>.
+ *
+ * \param pucRegBuffer If the application registers values should be updated the
+ *   buffer points to the new registers values. If the protocol stack needs
+ *   to now the current values the callback function should write them into
+ *   this buffer.
+ * \param usAddress The starting address of the register.
+ * \param usNRegs Number of registers to read or write.
+ * \param eMode If eMBRegisterMode::MB_REG_WRITE the application register 
+ *   values should be updated from the values in the buffer. For example
+ *   this would be the case when the Modbus master has issued an 
+ *   <b>WRITE SINGLE REGISTER</b> command.
+ *   If the value eMBRegisterMode::MB_REG_READ the application should copy 
+ *   the current values into the buffer \c pucRegBuffer.
+ *
+ * \return The function must return one of the following error codes:
+ *   - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
+ *       Modbus response is sent.
+ *   - eMBErrorCode::MB_ENOREG If the application can not supply values
+ *       for registers within this range. In this case a 
+ *       <b>ILLEGAL DATA ADDRESS</b> exception frame is sent as a response.
+ *   - eMBErrorCode::MB_ETIMEDOUT If the requested register block is
+ *       currently not available and the application dependent response
+ *       timeout would be violated. In this case a <b>SLAVE DEVICE BUSY</b>
+ *       exception is sent as a response.
+ *   - eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case
+ *       a <b>SLAVE DEVICE FAILURE</b> exception is sent as a response.
+ */
+eMBErrorCode    eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress,
+                                 USHORT usNRegs, eMBRegisterMode eMode );
+
+/*! \ingroup modbus_registers
+ * \brief Callback function used if a <em>Coil Register</em> value is
+ *   read or written by the protocol stack. If you are going to use
+ *   this function you might use the functions xMBUtilSetBits(  ) and
+ *   xMBUtilGetBits(  ) for working with bitfields.
+ *
+ * \param pucRegBuffer The bits are packed in bytes where the first coil
+ *   starting at address \c usAddress is stored in the LSB of the
+ *   first byte in the buffer <code>pucRegBuffer</code>.
+ *   If the buffer should be written by the callback function unused
+ *   coil values (I.e. if not a multiple of eight coils is used) should be set
+ *   to zero.
+ * \param usAddress The first coil number.
+ * \param usNCoils Number of coil values requested.
+ * \param eMode If eMBRegisterMode::MB_REG_WRITE the application values should
+ *   be updated from the values supplied in the buffer \c pucRegBuffer.
+ *   If eMBRegisterMode::MB_REG_READ the application should store the current
+ *   values in the buffer \c pucRegBuffer.
+ *
+ * \return The function must return one of the following error codes:
+ *   - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
+ *       Modbus response is sent.
+ *   - eMBErrorCode::MB_ENOREG If the application does not map an coils
+ *       within the requested address range. In this case a 
+ *       <b>ILLEGAL DATA ADDRESS</b> is sent as a response.
+ *   - eMBErrorCode::MB_ETIMEDOUT If the requested register block is
+ *       currently not available and the application dependent response
+ *       timeout would be violated. In this case a <b>SLAVE DEVICE BUSY</b>
+ *       exception is sent as a response.
+ *   - eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case
+ *       a <b>SLAVE DEVICE FAILURE</b> exception is sent as a response.
+ */
+eMBErrorCode    eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress,
+                               USHORT usNCoils, eMBRegisterMode eMode );
+
+/*! \ingroup modbus_registers
+ * \brief Callback function used if a <em>Input Discrete Register</em> value is
+ *   read by the protocol stack.
+ *
+ * If you are going to use his function you might use the functions
+ * xMBUtilSetBits(  ) and xMBUtilGetBits(  ) for working with bitfields.
+ *
+ * \param pucRegBuffer The buffer should be updated with the current
+ *   coil values. The first discrete input starting at \c usAddress must be
+ *   stored at the LSB of the first byte in the buffer. If the requested number
+ *   is not a multiple of eight the remaining bits should be set to zero.
+ * \param usAddress The starting address of the first discrete input.
+ * \param usNDiscrete Number of discrete input values.
+ * \return The function must return one of the following error codes:
+ *   - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
+ *       Modbus response is sent.
+ *   - eMBErrorCode::MB_ENOREG If no such discrete inputs exists.
+ *       In this case a <b>ILLEGAL DATA ADDRESS</b> exception frame is sent 
+ *       as a response.
+ *   - eMBErrorCode::MB_ETIMEDOUT If the requested register block is
+ *       currently not available and the application dependent response
+ *       timeout would be violated. In this case a <b>SLAVE DEVICE BUSY</b>
+ *       exception is sent as a response.
+ *   - eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case
+ *       a <b>SLAVE DEVICE FAILURE</b> exception is sent as a response.
+ */
+eMBErrorCode    eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress,
+                                  USHORT usNDiscrete );
+
+#ifdef __cplusplus
+PR_END_EXTERN_C
+#endif
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbconfig.h	Thu Apr 15 12:10:34 2010 +0000
@@ -0,0 +1,103 @@
+/* 
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * File: $Id: mbconfig.h,v 1.14 2006/12/07 22:10:34 wolti Exp $
+ */
+
+#ifndef _MB_CONFIG_H
+#define _MB_CONFIG_H
+
+#ifdef __cplusplus
+PR_BEGIN_EXTERN_C
+#endif
+/* ----------------------- Defines ------------------------------------------*/
+/*! \defgroup modbus_cfg Modbus Configuration
+ *
+ * Most modules in the protocol stack are completly optional and can be
+ * excluded. This is specially important if target resources are very small
+ * and program memory space should be saved.<br>
+ *
+ * All of these settings are available in the file <code>mbconfig.h</code>
+ */
+/*! \addtogroup modbus_cfg
+ *  @{
+ */
+/*! \brief If Modbus ASCII support is enabled. */
+#define MB_ASCII_ENABLED                        (  0 )
+/*! \brief If Modbus RTU support is enabled. */
+#define MB_RTU_ENABLED                          (  1 )
+/*! \brief If Modbus TCP support is enabled. */
+#define MB_TCP_ENABLED                          (  0 )
+/*! \brief The character timeout value for Modbus ASCII.
+ *
+ * The character timeout value is not fixed for Modbus ASCII and is therefore
+ * a configuration option. It should be set to the maximum expected delay
+ * time of the network.
+ */
+#define MB_ASCII_TIMEOUT_SEC                    (  0 )
+/*! \brief Maximum number of Modbus functions codes the protocol stack
+ *    should support.
+ *
+ * The maximum number of supported Modbus functions must be greater than
+ * the sum of all enabled functions in this file and custom function
+ * handlers. If set to small adding more functions will fail.
+ */
+#define MB_FUNC_HANDLERS_MAX                    ( 16 )
+/*! \brief Number of bytes which should be allocated for the <em>Report Slave ID
+ *    </em>command.
+ *
+ * This number limits the maximum size of the additional segment in the
+ * report slave id function. See eMBSetSlaveID(  ) for more information on
+ * how to set this value. It is only used if MB_FUNC_OTHER_REP_SLAVEID_ENABLED
+ * is set to <code>1</code>.
+ */
+#define MB_FUNC_OTHER_REP_SLAVEID_BUF           ( 32 )
+/*! \brief If the <em>Report Slave ID</em> function should be enabled. */
+#define MB_FUNC_OTHER_REP_SLAVEID_ENABLED       (  1 )
+/*! \brief If the <em>Read Input Registers</em> function should be enabled. */
+#define MB_FUNC_READ_INPUT_ENABLED              (  1 )
+/*! \brief If the <em>Read Holding Registers</em> function should be enabled. */
+#define MB_FUNC_READ_HOLDING_ENABLED            (  1 )
+/*! \brief If the <em>Write Single Register</em> function should be enabled. */
+#define MB_FUNC_WRITE_HOLDING_ENABLED           (  1 )
+/*! \brief If the <em>Write Multiple registers</em> function should be enabled. */
+#define MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED  (  1 )
+/*! \brief If the <em>Read Coils</em> function should be enabled. */
+#define MB_FUNC_READ_COILS_ENABLED              (  1 )
+/*! \brief If the <em>Write Coils</em> function should be enabled. */
+#define MB_FUNC_WRITE_COIL_ENABLED              (  1 )
+/*! \brief If the <em>Write Multiple Coils</em> function should be enabled. */
+#define MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED    (  1 )
+/*! \brief If the <em>Read Discrete Inputs</em> function should be enabled. */
+#define MB_FUNC_READ_DISCRETE_INPUTS_ENABLED    (  1 )
+/*! \brief If the <em>Read/Write Multiple Registers</em> function should be enabled. */
+#define MB_FUNC_READWRITE_HOLDING_ENABLED       (  1 )
+/*! @} */
+#ifdef __cplusplus
+PR_END_EXTERN_C
+#endif
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbcrc.cpp	Thu Apr 15 12:10:34 2010 +0000
@@ -0,0 +1,98 @@
+/* 
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * File: $Id: mbcrc.c,v 1.7 2007/02/18 23:50:27 wolti Exp $
+ */
+
+/* ----------------------- Platform includes --------------------------------*/
+#include "port.h"
+
+static const UCHAR aucCRCHi[] = {
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+    0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 
+    0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+    0x00, 0xC1, 0x81, 0x40
+};
+
+static const UCHAR aucCRCLo[] = {
+    0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,
+    0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
+    0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9,
+    0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
+    0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
+    0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
+    0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
+    0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 
+    0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF,
+    0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
+    0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1,
+    0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
+    0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 
+    0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
+    0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
+    0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
+    0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97,
+    0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E,
+    0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89,
+    0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
+    0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
+    0x41, 0x81, 0x80, 0x40
+};
+
+USHORT
+usMBCRC16( UCHAR * pucFrame, USHORT usLen )
+{
+    UCHAR           ucCRCHi = 0xFF;
+    UCHAR           ucCRCLo = 0xFF;
+    int             iIndex;
+
+    while( usLen-- )
+    {
+        iIndex = ucCRCLo ^ *( pucFrame++ );
+        ucCRCLo = ( UCHAR )( ucCRCHi ^ aucCRCHi[iIndex] );
+        ucCRCHi = aucCRCLo[iIndex];
+    }
+    return ( USHORT )( ucCRCHi << 8 | ucCRCLo );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbcrc.h	Thu Apr 15 12:10:34 2010 +0000
@@ -0,0 +1,36 @@
+/* 
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * File: $Id: mbcrc.h,v 1.5 2006/12/07 22:10:34 wolti Exp $
+ */
+
+#ifndef _MB_CRC_H
+#define _MB_CRC_H
+
+USHORT          usMBCRC16( UCHAR * pucFrame, USHORT usLen );
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Thu Apr 15 12:10:34 2010 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/49a220cc26e0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbframe.h	Thu Apr 15 12:10:34 2010 +0000
@@ -0,0 +1,87 @@
+/* 
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * File: $Id: mbframe.h,v 1.9 2006/12/07 22:10:34 wolti Exp $
+ */
+
+#ifndef _MB_FRAME_H
+#define _MB_FRAME_H
+
+#ifdef __cplusplus
+PR_BEGIN_EXTERN_C
+#endif
+
+/*!
+ * Constants which defines the format of a modbus frame. The example is
+ * shown for a Modbus RTU/ASCII frame. Note that the Modbus PDU is not
+ * dependent on the underlying transport.
+ *
+ * <code>
+ * <------------------------ MODBUS SERIAL LINE PDU (1) ------------------->
+ *              <----------- MODBUS PDU (1') ---------------->
+ *  +-----------+---------------+----------------------------+-------------+
+ *  | Address   | Function Code | Data                       | CRC/LRC     |
+ *  +-----------+---------------+----------------------------+-------------+
+ *  |           |               |                                   |
+ * (2)        (3/2')           (3')                                (4)
+ *
+ * (1)  ... MB_SER_PDU_SIZE_MAX = 256
+ * (2)  ... MB_SER_PDU_ADDR_OFF = 0
+ * (3)  ... MB_SER_PDU_PDU_OFF  = 1
+ * (4)  ... MB_SER_PDU_SIZE_CRC = 2
+ *
+ * (1') ... MB_PDU_SIZE_MAX     = 253
+ * (2') ... MB_PDU_FUNC_OFF     = 0
+ * (3') ... MB_PDU_DATA_OFF     = 1
+ * </code>
+ */
+
+/* ----------------------- Defines ------------------------------------------*/
+#define MB_PDU_SIZE_MAX     253 /*!< Maximum size of a PDU. */
+#define MB_PDU_SIZE_MIN     1   /*!< Function Code */
+#define MB_PDU_FUNC_OFF     0   /*!< Offset of function code in PDU. */
+#define MB_PDU_DATA_OFF     1   /*!< Offset for response data in PDU. */
+
+/* ----------------------- Prototypes  0-------------------------------------*/
+typedef void    ( *pvMBFrameStart ) ( void );
+
+typedef void    ( *pvMBFrameStop ) ( void );
+
+typedef eMBErrorCode( *peMBFrameReceive ) ( UCHAR * pucRcvAddress,
+                                            UCHAR ** pucFrame,
+                                            USHORT * pusLength );
+
+typedef eMBErrorCode( *peMBFrameSend ) ( UCHAR slaveAddress,
+                                         const UCHAR * pucFrame,
+                                         USHORT usLength );
+
+typedef void( *pvMBFrameClose ) ( void );
+
+#ifdef __cplusplus
+PR_END_EXTERN_C
+#endif
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbfunc.h	Thu Apr 15 12:10:34 2010 +0000
@@ -0,0 +1,80 @@
+/* 
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * File: $Id: mbfunc.h,v 1.12 2006/12/07 22:10:34 wolti Exp $
+ */
+
+#ifndef _MB_FUNC_H
+#define _MB_FUNC_H
+
+#ifdef __cplusplus
+PR_BEGIN_EXTERN_C
+#endif
+#if MB_FUNC_OTHER_REP_SLAVEID_BUF > 0
+    eMBException eMBFuncReportSlaveID( UCHAR * pucFrame, USHORT * usLen );
+#endif
+
+#if MB_FUNC_READ_INPUT_ENABLED > 0
+eMBException    eMBFuncReadInputRegister( UCHAR * pucFrame, USHORT * usLen );
+#endif
+
+#if MB_FUNC_READ_HOLDING_ENABLED > 0
+eMBException    eMBFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen );
+#endif
+
+#if MB_FUNC_WRITE_HOLDING_ENABLED > 0
+eMBException    eMBFuncWriteHoldingRegister( UCHAR * pucFrame, USHORT * usLen );
+#endif
+
+#if MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED > 0
+eMBException    eMBFuncWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen );
+#endif
+
+#if MB_FUNC_READ_COILS_ENABLED > 0
+eMBException    eMBFuncReadCoils( UCHAR * pucFrame, USHORT * usLen );
+#endif
+
+#if MB_FUNC_WRITE_COIL_ENABLED > 0
+eMBException    eMBFuncWriteCoil( UCHAR * pucFrame, USHORT * usLen );
+#endif
+
+#if MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED > 0
+eMBException    eMBFuncWriteMultipleCoils( UCHAR * pucFrame, USHORT * usLen );
+#endif
+
+#if MB_FUNC_READ_DISCRETE_INPUTS_ENABLED > 0
+eMBException    eMBFuncReadDiscreteInputs( UCHAR * pucFrame, USHORT * usLen );
+#endif
+
+#if MB_FUNC_READWRITE_HOLDING_ENABLED > 0
+eMBException    eMBFuncReadWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen );
+#endif
+
+#ifdef __cplusplus
+PR_END_EXTERN_C
+#endif
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbfunccoils.cpp	Thu Apr 15 12:10:34 2010 +0000
@@ -0,0 +1,270 @@
+/* 
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * File: $Id: mbfunccoils.c,v 1.8 2007/02/18 23:47:16 wolti Exp $
+ */
+
+/* ----------------------- System includes ----------------------------------*/
+#include "stdlib.h"
+#include "string.h"
+
+/* ----------------------- Platform includes --------------------------------*/
+#include "port.h"
+
+/* ----------------------- Modbus includes ----------------------------------*/
+#include "mb.h"
+#include "mbframe.h"
+#include "mbproto.h"
+#include "mbconfig.h"
+
+/* ----------------------- Defines ------------------------------------------*/
+#define MB_PDU_FUNC_READ_ADDR_OFF           ( MB_PDU_DATA_OFF )
+#define MB_PDU_FUNC_READ_COILCNT_OFF        ( MB_PDU_DATA_OFF + 2 )
+#define MB_PDU_FUNC_READ_SIZE               ( 4 )
+#define MB_PDU_FUNC_READ_COILCNT_MAX        ( 0x07D0 )
+
+#define MB_PDU_FUNC_WRITE_ADDR_OFF          ( MB_PDU_DATA_OFF )
+#define MB_PDU_FUNC_WRITE_VALUE_OFF         ( MB_PDU_DATA_OFF + 2 )
+#define MB_PDU_FUNC_WRITE_SIZE              ( 4 )
+
+#define MB_PDU_FUNC_WRITE_MUL_ADDR_OFF      ( MB_PDU_DATA_OFF )
+#define MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF   ( MB_PDU_DATA_OFF + 2 )
+#define MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF   ( MB_PDU_DATA_OFF + 4 )
+#define MB_PDU_FUNC_WRITE_MUL_VALUES_OFF    ( MB_PDU_DATA_OFF + 5 )
+#define MB_PDU_FUNC_WRITE_MUL_SIZE_MIN      ( 5 )
+#define MB_PDU_FUNC_WRITE_MUL_COILCNT_MAX   ( 0x07B0 )
+
+/* ----------------------- Static functions ---------------------------------*/
+eMBException    prveMBError2Exception( eMBErrorCode eErrorCode );
+
+/* ----------------------- Start implementation -----------------------------*/
+
+#if MB_FUNC_READ_COILS_ENABLED > 0
+
+eMBException
+eMBFuncReadCoils( UCHAR * pucFrame, USHORT * usLen )
+{
+    USHORT          usRegAddress;
+    USHORT          usCoilCount;
+    UCHAR           ucNBytes;
+    UCHAR          *pucFrameCur;
+
+    eMBException    eStatus = MB_EX_NONE;
+    eMBErrorCode    eRegStatus;
+
+    if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
+    {
+        usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
+        usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
+        usRegAddress++;
+
+        usCoilCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_COILCNT_OFF] << 8 );
+        usCoilCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_COILCNT_OFF + 1] );
+
+        /* Check if the number of registers to read is valid. If not
+         * return Modbus illegal data value exception. 
+         */
+        if( ( usCoilCount >= 1 ) &&
+            ( usCoilCount < MB_PDU_FUNC_READ_COILCNT_MAX ) )
+        {
+            /* Set the current PDU data pointer to the beginning. */
+            pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
+            *usLen = MB_PDU_FUNC_OFF;
+
+            /* First byte contains the function code. */
+            *pucFrameCur++ = MB_FUNC_READ_COILS;
+            *usLen += 1;
+
+            /* Test if the quantity of coils is a multiple of 8. If not last
+             * byte is only partially field with unused coils set to zero. */
+            if( ( usCoilCount & 0x0007 ) != 0 )
+            {
+                ucNBytes = ( UCHAR )( usCoilCount / 8 + 1 );
+            }
+            else
+            {
+                ucNBytes = ( UCHAR )( usCoilCount / 8 );
+            }
+            *pucFrameCur++ = ucNBytes;
+            *usLen += 1;
+
+            eRegStatus =
+                eMBRegCoilsCB( pucFrameCur, usRegAddress, usCoilCount,
+                               MB_REG_READ );
+
+            /* If an error occured convert it into a Modbus exception. */
+            if( eRegStatus != MB_ENOERR )
+            {
+                eStatus = prveMBError2Exception( eRegStatus );
+            }
+            else
+            {
+                /* The response contains the function code, the starting address
+                 * and the quantity of registers. We reuse the old values in the 
+                 * buffer because they are still valid. */
+                *usLen += ucNBytes;;
+            }
+        }
+        else
+        {
+            eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+        }
+    }
+    else
+    {
+        /* Can't be a valid read coil register request because the length
+         * is incorrect. */
+        eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+    }
+    return eStatus;
+}
+
+#if MB_FUNC_WRITE_COIL_ENABLED > 0
+eMBException
+eMBFuncWriteCoil( UCHAR * pucFrame, USHORT * usLen )
+{
+    USHORT          usRegAddress;
+    UCHAR           ucBuf[2];
+
+    eMBException    eStatus = MB_EX_NONE;
+    eMBErrorCode    eRegStatus;
+
+    if( *usLen == ( MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN ) )
+    {
+        usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF] << 8 );
+        usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF + 1] );
+        usRegAddress++;
+
+        if( ( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF + 1] == 0x00 ) &&
+            ( ( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0xFF ) ||
+              ( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0x00 ) ) )
+        {
+            ucBuf[1] = 0;
+            if( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0xFF )
+            {
+                ucBuf[0] = 1;
+            }
+            else
+            {
+                ucBuf[0] = 0;
+            }
+            eRegStatus =
+                eMBRegCoilsCB( &ucBuf[0], usRegAddress, 1, MB_REG_WRITE );
+
+            /* If an error occured convert it into a Modbus exception. */
+            if( eRegStatus != MB_ENOERR )
+            {
+                eStatus = prveMBError2Exception( eRegStatus );
+            }
+        }
+        else
+        {
+            eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+        }
+    }
+    else
+    {
+        /* Can't be a valid write coil register request because the length
+         * is incorrect. */
+        eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+    }
+    return eStatus;
+}
+
+#endif
+
+#if MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED > 0
+eMBException
+eMBFuncWriteMultipleCoils( UCHAR * pucFrame, USHORT * usLen )
+{
+    USHORT          usRegAddress;
+    USHORT          usCoilCnt;
+    UCHAR           ucByteCount;
+    UCHAR           ucByteCountVerify;
+
+    eMBException    eStatus = MB_EX_NONE;
+    eMBErrorCode    eRegStatus;
+
+    if( *usLen > ( MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN ) )
+    {
+        usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF] << 8 );
+        usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF + 1] );
+        usRegAddress++;
+
+        usCoilCnt = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF] << 8 );
+        usCoilCnt |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF + 1] );
+
+        ucByteCount = pucFrame[MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF];
+
+        /* Compute the number of expected bytes in the request. */
+        if( ( usCoilCnt & 0x0007 ) != 0 )
+        {
+            ucByteCountVerify = ( UCHAR )( usCoilCnt / 8 + 1 );
+        }
+        else
+        {
+            ucByteCountVerify = ( UCHAR )( usCoilCnt / 8 );
+        }
+
+        if( ( usCoilCnt >= 1 ) &&
+            ( usCoilCnt <= MB_PDU_FUNC_WRITE_MUL_COILCNT_MAX ) &&
+            ( ucByteCountVerify == ucByteCount ) )
+        {
+            eRegStatus =
+                eMBRegCoilsCB( &pucFrame[MB_PDU_FUNC_WRITE_MUL_VALUES_OFF],
+                               usRegAddress, usCoilCnt, MB_REG_WRITE );
+
+            /* If an error occured convert it into a Modbus exception. */
+            if( eRegStatus != MB_ENOERR )
+            {
+                eStatus = prveMBError2Exception( eRegStatus );
+            }
+            else
+            {
+                /* The response contains the function code, the starting address
+                 * and the quantity of registers. We reuse the old values in the 
+                 * buffer because they are still valid. */
+                *usLen = MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF;
+            }
+        }
+        else
+        {
+            eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+        }
+    }
+    else
+    {
+        /* Can't be a valid write coil register request because the length
+         * is incorrect. */
+        eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+    }
+    return eStatus;
+}
+
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbfuncdiag.cpp	Thu Apr 15 12:10:34 2010 +0000
@@ -0,0 +1,29 @@
+/* 
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * File: $Id: mbfuncdiag.c,v 1.3 2006/12/07 22:10:34 wolti Exp $
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbfuncdisc.cpp	Thu Apr 15 12:10:34 2010 +0000
@@ -0,0 +1,125 @@
+ /*
+  * FreeRTOS Modbus Libary: A Modbus serial implementation for FreeRTOS
+  * Copyright (C) 2006 Christian Walter <wolti@sil.at>
+  *
+  * This library is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU Lesser General Public
+  * License as published by the Free Software Foundation; either
+  * version 2.1 of the License, or (at your option) any later version.
+  *
+  * This library is distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  * Lesser General Public License for more details.
+  *
+  * You should have received a copy of the GNU Lesser General Public
+  * License along with this library; if not, write to the Free Software
+  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+  */
+
+
+
+/* ----------------------- System includes ----------------------------------*/
+#include "stdlib.h"
+#include "string.h"
+
+/* ----------------------- Platform includes --------------------------------*/
+#include "port.h"
+
+/* ----------------------- Modbus includes ----------------------------------*/
+#include "mb.h"
+#include "mbframe.h"
+#include "mbproto.h"
+#include "mbconfig.h"
+
+/* ----------------------- Defines ------------------------------------------*/
+#define MB_PDU_FUNC_READ_ADDR_OFF           ( MB_PDU_DATA_OFF )
+#define MB_PDU_FUNC_READ_DISCCNT_OFF        ( MB_PDU_DATA_OFF + 2 )
+#define MB_PDU_FUNC_READ_SIZE               ( 4 )
+#define MB_PDU_FUNC_READ_DISCCNT_MAX        ( 0x07D0 )
+
+/* ----------------------- Static functions ---------------------------------*/
+eMBException    prveMBError2Exception( eMBErrorCode eErrorCode );
+
+/* ----------------------- Start implementation -----------------------------*/
+
+#if MB_FUNC_READ_COILS_ENABLED > 0
+
+eMBException
+eMBFuncReadDiscreteInputs( UCHAR * pucFrame, USHORT * usLen )
+{
+    USHORT          usRegAddress;
+    USHORT          usDiscreteCnt;
+    UCHAR           ucNBytes;
+    UCHAR          *pucFrameCur;
+
+    eMBException    eStatus = MB_EX_NONE;
+    eMBErrorCode    eRegStatus;
+
+    if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
+    {
+        usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
+        usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
+        usRegAddress++;
+
+        usDiscreteCnt = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_DISCCNT_OFF] << 8 );
+        usDiscreteCnt |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_DISCCNT_OFF + 1] );
+
+        /* Check if the number of registers to read is valid. If not
+         * return Modbus illegal data value exception. 
+         */
+        if( ( usDiscreteCnt >= 1 ) &&
+            ( usDiscreteCnt < MB_PDU_FUNC_READ_DISCCNT_MAX ) )
+        {
+            /* Set the current PDU data pointer to the beginning. */
+            pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
+            *usLen = MB_PDU_FUNC_OFF;
+
+            /* First byte contains the function code. */
+            *pucFrameCur++ = MB_FUNC_READ_DISCRETE_INPUTS;
+            *usLen += 1;
+
+            /* Test if the quantity of coils is a multiple of 8. If not last
+             * byte is only partially field with unused coils set to zero. */
+            if( ( usDiscreteCnt & 0x0007 ) != 0 )
+            {
+                ucNBytes = ( UCHAR ) ( usDiscreteCnt / 8 + 1 );
+            }
+            else
+            {
+                ucNBytes = ( UCHAR ) ( usDiscreteCnt / 8 );
+            }
+            *pucFrameCur++ = ucNBytes;
+            *usLen += 1;
+
+            eRegStatus =
+                eMBRegDiscreteCB( pucFrameCur, usRegAddress, usDiscreteCnt );
+
+            /* If an error occured convert it into a Modbus exception. */
+            if( eRegStatus != MB_ENOERR )
+            {
+                eStatus = prveMBError2Exception( eRegStatus );
+            }
+            else
+            {
+                /* The response contains the function code, the starting address
+                 * and the quantity of registers. We reuse the old values in the 
+                 * buffer because they are still valid. */
+                *usLen += ucNBytes;;
+            }
+        }
+        else
+        {
+            eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+        }
+    }
+    else
+    {
+        /* Can't be a valid read coil register request because the length
+         * is incorrect. */
+        eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+    }
+    return eStatus;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbfuncholding.cpp	Thu Apr 15 12:10:34 2010 +0000
@@ -0,0 +1,308 @@
+/* 
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * File: $Id: mbfuncholding.c,v 1.12 2007/02/18 23:48:22 wolti Exp $
+ */
+
+/* ----------------------- System includes ----------------------------------*/
+#include "stdlib.h"
+#include "string.h"
+
+/* ----------------------- Platform includes --------------------------------*/
+#include "port.h"
+
+/* ----------------------- Modbus includes ----------------------------------*/
+#include "mb.h"
+#include "mbframe.h"
+#include "mbproto.h"
+#include "mbconfig.h"
+
+/* ----------------------- Defines ------------------------------------------*/
+#define MB_PDU_FUNC_READ_ADDR_OFF               ( MB_PDU_DATA_OFF + 0)
+#define MB_PDU_FUNC_READ_REGCNT_OFF             ( MB_PDU_DATA_OFF + 2 )
+#define MB_PDU_FUNC_READ_SIZE                   ( 4 )
+#define MB_PDU_FUNC_READ_REGCNT_MAX             ( 0x007D )
+
+#define MB_PDU_FUNC_WRITE_ADDR_OFF              ( MB_PDU_DATA_OFF + 0)
+#define MB_PDU_FUNC_WRITE_VALUE_OFF             ( MB_PDU_DATA_OFF + 2 )
+#define MB_PDU_FUNC_WRITE_SIZE                  ( 4 )
+
+#define MB_PDU_FUNC_WRITE_MUL_ADDR_OFF          ( MB_PDU_DATA_OFF + 0 )
+#define MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF        ( MB_PDU_DATA_OFF + 2 )
+#define MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF       ( MB_PDU_DATA_OFF + 4 )
+#define MB_PDU_FUNC_WRITE_MUL_VALUES_OFF        ( MB_PDU_DATA_OFF + 5 )
+#define MB_PDU_FUNC_WRITE_MUL_SIZE_MIN          ( 5 )
+#define MB_PDU_FUNC_WRITE_MUL_REGCNT_MAX        ( 0x0078 )
+
+#define MB_PDU_FUNC_READWRITE_READ_ADDR_OFF     ( MB_PDU_DATA_OFF + 0 )
+#define MB_PDU_FUNC_READWRITE_READ_REGCNT_OFF   ( MB_PDU_DATA_OFF + 2 )
+#define MB_PDU_FUNC_READWRITE_WRITE_ADDR_OFF    ( MB_PDU_DATA_OFF + 4 )
+#define MB_PDU_FUNC_READWRITE_WRITE_REGCNT_OFF  ( MB_PDU_DATA_OFF + 6 )
+#define MB_PDU_FUNC_READWRITE_BYTECNT_OFF       ( MB_PDU_DATA_OFF + 8 )
+#define MB_PDU_FUNC_READWRITE_WRITE_VALUES_OFF  ( MB_PDU_DATA_OFF + 9 )
+#define MB_PDU_FUNC_READWRITE_SIZE_MIN          ( 9 )
+
+/* ----------------------- Static functions ---------------------------------*/
+eMBException    prveMBError2Exception( eMBErrorCode eErrorCode );
+
+/* ----------------------- Start implementation -----------------------------*/
+
+#if MB_FUNC_WRITE_HOLDING_ENABLED > 0
+
+eMBException
+eMBFuncWriteHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
+{
+    USHORT          usRegAddress;
+    eMBException    eStatus = MB_EX_NONE;
+    eMBErrorCode    eRegStatus;
+
+    if( *usLen == ( MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN ) )
+    {
+        usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF] << 8 );
+        usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF + 1] );
+        usRegAddress++;
+
+        /* Make callback to update the value. */
+        eRegStatus = eMBRegHoldingCB( &pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF],
+                                      usRegAddress, 1, MB_REG_WRITE );
+
+        /* If an error occured convert it into a Modbus exception. */
+        if( eRegStatus != MB_ENOERR )
+        {
+            eStatus = prveMBError2Exception( eRegStatus );
+        }
+    }
+    else
+    {
+        /* Can't be a valid request because the length is incorrect. */
+        eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+    }
+    return eStatus;
+}
+#endif
+
+#if MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED > 0
+eMBException
+eMBFuncWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
+{
+    USHORT          usRegAddress;
+    USHORT          usRegCount;
+    UCHAR           ucRegByteCount;
+
+    eMBException    eStatus = MB_EX_NONE;
+    eMBErrorCode    eRegStatus;
+
+    if( *usLen >= ( MB_PDU_FUNC_WRITE_MUL_SIZE_MIN + MB_PDU_SIZE_MIN ) )
+    {
+        usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF] << 8 );
+        usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF + 1] );
+        usRegAddress++;
+
+        usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF] << 8 );
+        usRegCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF + 1] );
+
+        ucRegByteCount = pucFrame[MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF];
+
+        if( ( usRegCount >= 1 ) &&
+            ( usRegCount <= MB_PDU_FUNC_WRITE_MUL_REGCNT_MAX ) &&
+            ( ucRegByteCount == ( UCHAR ) ( 2 * usRegCount ) ) )
+        {
+            /* Make callback to update the register values. */
+            eRegStatus =
+                eMBRegHoldingCB( &pucFrame[MB_PDU_FUNC_WRITE_MUL_VALUES_OFF],
+                                 usRegAddress, usRegCount, MB_REG_WRITE );
+
+            /* If an error occured convert it into a Modbus exception. */
+            if( eRegStatus != MB_ENOERR )
+            {
+                eStatus = prveMBError2Exception( eRegStatus );
+            }
+            else
+            {
+                /* The response contains the function code, the starting
+                 * address and the quantity of registers. We reuse the
+                 * old values in the buffer because they are still valid.
+                 */
+                *usLen = MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF;
+            }
+        }
+        else
+        {
+            eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+        }
+    }
+    else
+    {
+        /* Can't be a valid request because the length is incorrect. */
+        eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+    }
+    return eStatus;
+}
+#endif
+
+#if MB_FUNC_READ_HOLDING_ENABLED > 0
+
+eMBException
+eMBFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
+{
+    USHORT          usRegAddress;
+    USHORT          usRegCount;
+    UCHAR          *pucFrameCur;
+
+    eMBException    eStatus = MB_EX_NONE;
+    eMBErrorCode    eRegStatus;
+
+    if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
+    {
+        usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
+        usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
+        usRegAddress++;
+
+        usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] << 8 );
+        usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );
+
+        /* Check if the number of registers to read is valid. If not
+         * return Modbus illegal data value exception. 
+         */
+        if( ( usRegCount >= 1 ) && ( usRegCount <= MB_PDU_FUNC_READ_REGCNT_MAX ) )
+        {
+            /* Set the current PDU data pointer to the beginning. */
+            pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
+            *usLen = MB_PDU_FUNC_OFF;
+
+            /* First byte contains the function code. */
+            *pucFrameCur++ = MB_FUNC_READ_HOLDING_REGISTER;
+            *usLen += 1;
+
+            /* Second byte in the response contain the number of bytes. */
+            *pucFrameCur++ = ( UCHAR ) ( usRegCount * 2 );
+            *usLen += 1;
+
+            /* Make callback to fill the buffer. */
+            eRegStatus = eMBRegHoldingCB( pucFrameCur, usRegAddress, usRegCount, MB_REG_READ );
+            /* If an error occured convert it into a Modbus exception. */
+            if( eRegStatus != MB_ENOERR )
+            {
+                eStatus = prveMBError2Exception( eRegStatus );
+            }
+            else
+            {
+                *usLen += usRegCount * 2;
+            }
+        }
+        else
+        {
+            eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+        }
+    }
+    else
+    {
+        /* Can't be a valid request because the length is incorrect. */
+        eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+    }
+    return eStatus;
+}
+
+#endif
+
+#if MB_FUNC_READWRITE_HOLDING_ENABLED > 0
+
+eMBException
+eMBFuncReadWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
+{
+    USHORT          usRegReadAddress;
+    USHORT          usRegReadCount;
+    USHORT          usRegWriteAddress;
+    USHORT          usRegWriteCount;
+    UCHAR           ucRegWriteByteCount;
+    UCHAR          *pucFrameCur;
+
+    eMBException    eStatus = MB_EX_NONE;
+    eMBErrorCode    eRegStatus;
+
+    if( *usLen >= ( MB_PDU_FUNC_READWRITE_SIZE_MIN + MB_PDU_SIZE_MIN ) )
+    {
+        usRegReadAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_READ_ADDR_OFF] << 8U );
+        usRegReadAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_READ_ADDR_OFF + 1] );
+        usRegReadAddress++;
+
+        usRegReadCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_READ_REGCNT_OFF] << 8U );
+        usRegReadCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_READ_REGCNT_OFF + 1] );
+
+        usRegWriteAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_ADDR_OFF] << 8U );
+        usRegWriteAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_ADDR_OFF + 1] );
+        usRegWriteAddress++;
+
+        usRegWriteCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_REGCNT_OFF] << 8U );
+        usRegWriteCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_REGCNT_OFF + 1] );
+
+        ucRegWriteByteCount = pucFrame[MB_PDU_FUNC_READWRITE_BYTECNT_OFF];
+
+        if( ( usRegReadCount >= 1 ) && ( usRegReadCount <= 0x7D ) &&
+            ( usRegWriteCount >= 1 ) && ( usRegWriteCount <= 0x79 ) &&
+            ( ( 2 * usRegWriteCount ) == ucRegWriteByteCount ) )
+        {
+            /* Make callback to update the register values. */
+            eRegStatus = eMBRegHoldingCB( &pucFrame[MB_PDU_FUNC_READWRITE_WRITE_VALUES_OFF],
+                                          usRegWriteAddress, usRegWriteCount, MB_REG_WRITE );
+
+            if( eRegStatus == MB_ENOERR )
+            {
+                /* Set the current PDU data pointer to the beginning. */
+                pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
+                *usLen = MB_PDU_FUNC_OFF;
+
+                /* First byte contains the function code. */
+                *pucFrameCur++ = MB_FUNC_READWRITE_MULTIPLE_REGISTERS;
+                *usLen += 1;
+
+                /* Second byte in the response contain the number of bytes. */
+                *pucFrameCur++ = ( UCHAR ) ( usRegReadCount * 2 );
+                *usLen += 1;
+
+                /* Make the read callback. */
+                eRegStatus =
+                    eMBRegHoldingCB( pucFrameCur, usRegReadAddress, usRegReadCount, MB_REG_READ );
+                if( eRegStatus == MB_ENOERR )
+                {
+                    *usLen += 2 * usRegReadCount;
+                }
+            }
+            if( eRegStatus != MB_ENOERR )
+            {
+                eStatus = prveMBError2Exception( eRegStatus );
+            }
+        }
+        else
+        {
+            eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+        }
+    }
+    return eStatus;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbfuncinput.cpp	Thu Apr 15 12:10:34 2010 +0000
@@ -0,0 +1,121 @@
+/* 
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * File: $Id: mbfuncinput.c,v 1.10 2007/09/12 10:15:56 wolti Exp $
+ */
+
+/* ----------------------- System includes ----------------------------------*/
+#include "stdlib.h"
+#include "string.h"
+
+/* ----------------------- Platform includes --------------------------------*/
+#include "port.h"
+
+/* ----------------------- Modbus includes ----------------------------------*/
+#include "mb.h"
+#include "mbframe.h"
+#include "mbproto.h"
+#include "mbconfig.h"
+
+/* ----------------------- Defines ------------------------------------------*/
+#define MB_PDU_FUNC_READ_ADDR_OFF           ( MB_PDU_DATA_OFF )
+#define MB_PDU_FUNC_READ_REGCNT_OFF         ( MB_PDU_DATA_OFF + 2 )
+#define MB_PDU_FUNC_READ_SIZE               ( 4 )
+#define MB_PDU_FUNC_READ_REGCNT_MAX         ( 0x007D )
+
+#define MB_PDU_FUNC_READ_RSP_BYTECNT_OFF    ( MB_PDU_DATA_OFF )
+
+/* ----------------------- Static functions ---------------------------------*/
+eMBException    prveMBError2Exception( eMBErrorCode eErrorCode );
+
+/* ----------------------- Start implementation -----------------------------*/
+#if MB_FUNC_READ_INPUT_ENABLED > 0
+
+eMBException
+eMBFuncReadInputRegister( UCHAR * pucFrame, USHORT * usLen )
+{
+    USHORT          usRegAddress;
+    USHORT          usRegCount;
+    UCHAR          *pucFrameCur;
+
+    eMBException    eStatus = MB_EX_NONE;
+    eMBErrorCode    eRegStatus;
+
+    if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
+    {
+        usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
+        usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
+        usRegAddress++;
+
+        usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] << 8 );
+        usRegCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );
+
+        /* Check if the number of registers to read is valid. If not
+         * return Modbus illegal data value exception. 
+         */
+        if( ( usRegCount >= 1 )
+            && ( usRegCount < MB_PDU_FUNC_READ_REGCNT_MAX ) )
+        {
+            /* Set the current PDU data pointer to the beginning. */
+            pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
+            *usLen = MB_PDU_FUNC_OFF;
+
+            /* First byte contains the function code. */
+            *pucFrameCur++ = MB_FUNC_READ_INPUT_REGISTER;
+            *usLen += 1;
+
+            /* Second byte in the response contain the number of bytes. */
+            *pucFrameCur++ = ( UCHAR )( usRegCount * 2 );
+            *usLen += 1;
+
+            eRegStatus = eMBRegInputCB( pucFrameCur, usRegAddress, usRegCount );
+
+            /* If an error occured convert it into a Modbus exception. */
+            if( eRegStatus != MB_ENOERR )
+            {
+                eStatus = prveMBError2Exception( eRegStatus );
+            }
+            else
+            {
+                *usLen += usRegCount * 2;
+            }
+        }
+        else
+        {
+            eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+        }
+    }
+    else
+    {
+        /* Can't be a valid read input register request because the length
+         * is incorrect. */
+        eStatus = MB_EX_ILLEGAL_DATA_VALUE;
+    }
+    return eStatus;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbfuncother.cpp	Thu Apr 15 12:10:34 2010 +0000
@@ -0,0 +1,88 @@
+/* 
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * File: $Id: mbfuncother.c,v 1.8 2006/12/07 22:10:34 wolti Exp $
+ */
+
+/* ----------------------- System includes ----------------------------------*/
+#include "stdlib.h"
+#include "string.h"
+
+/* ----------------------- Platform includes --------------------------------*/
+#include "port.h"
+
+/* ----------------------- Modbus includes ----------------------------------*/
+#include "mb.h"
+#include "mbframe.h"
+#include "mbproto.h"
+#include "mbconfig.h"
+
+#if MB_FUNC_OTHER_REP_SLAVEID_ENABLED > 0
+
+/* ----------------------- Static variables ---------------------------------*/
+static UCHAR    ucMBSlaveID[MB_FUNC_OTHER_REP_SLAVEID_BUF];
+static USHORT   usMBSlaveIDLen;
+
+/* ----------------------- Start implementation -----------------------------*/
+
+eMBErrorCode
+eMBSetSlaveID( UCHAR ucSlaveID, BOOL xIsRunning,
+               UCHAR const *pucAdditional, USHORT usAdditionalLen )
+{
+    eMBErrorCode    eStatus = MB_ENOERR;
+
+    /* the first byte and second byte in the buffer is reserved for
+     * the parameter ucSlaveID and the running flag. The rest of
+     * the buffer is available for additional data. */
+    if( usAdditionalLen + 2 < MB_FUNC_OTHER_REP_SLAVEID_BUF )
+    {
+        usMBSlaveIDLen = 0;
+        ucMBSlaveID[usMBSlaveIDLen++] = ucSlaveID;
+        ucMBSlaveID[usMBSlaveIDLen++] = ( UCHAR )( xIsRunning ? 0xFF : 0x00 );
+        if( usAdditionalLen > 0 )
+        {
+            memcpy( &ucMBSlaveID[usMBSlaveIDLen], pucAdditional,
+                    ( size_t )usAdditionalLen );
+            usMBSlaveIDLen += usAdditionalLen;
+        }
+    }
+    else
+    {
+        eStatus = MB_ENORES;
+    }
+    return eStatus;
+}
+
+eMBException
+eMBFuncReportSlaveID( UCHAR * pucFrame, USHORT * usLen )
+{
+    memcpy( &pucFrame[MB_PDU_DATA_OFF], &ucMBSlaveID[0], ( size_t )usMBSlaveIDLen );
+    *usLen = ( USHORT )( MB_PDU_DATA_OFF + usMBSlaveIDLen );
+    return MB_EX_NONE;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbport.h	Thu Apr 15 12:10:34 2010 +0000
@@ -0,0 +1,127 @@
+/* 
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * File: $Id: mbport.h,v 1.17 2006/12/07 22:10:34 wolti Exp $
+ */
+
+#ifndef _MB_PORT_H
+#define _MB_PORT_H
+
+#ifdef __cplusplus
+PR_BEGIN_EXTERN_C
+#endif
+
+/* ----------------------- Type definitions ---------------------------------*/
+
+typedef enum
+{
+    EV_READY,                   /*!< Startup finished. */
+    EV_FRAME_RECEIVED,          /*!< Frame received. */
+    EV_EXECUTE,                 /*!< Execute function. */
+    EV_FRAME_SENT               /*!< Frame sent. */
+} eMBEventType;
+
+/*! \ingroup modbus
+ * \brief Parity used for characters in serial mode.
+ *
+ * The parity which should be applied to the characters sent over the serial
+ * link. Please note that this values are actually passed to the porting
+ * layer and therefore not all parity modes might be available.
+ */
+typedef enum
+{
+    MB_PAR_NONE,                /*!< No parity. */
+    MB_PAR_ODD,                 /*!< Odd parity. */
+    MB_PAR_EVEN                 /*!< Even parity. */
+} eMBParity;
+
+/* ----------------------- Supporting functions -----------------------------*/
+BOOL            xMBPortEventInit( void );
+
+BOOL            xMBPortEventPost( eMBEventType eEvent );
+
+BOOL            xMBPortEventGet(  /*@out@ */ eMBEventType * eEvent );
+
+/* ----------------------- Serial port functions ----------------------------*/
+
+BOOL            xMBPortSerialInit( UCHAR ucPort, ULONG ulBaudRate,
+                                   UCHAR ucDataBits, eMBParity eParity );
+
+void            vMBPortClose( void );
+
+void            xMBPortSerialClose( void );
+
+void            vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable );
+
+INLINE BOOL     xMBPortSerialGetByte( CHAR * pucByte );
+
+INLINE BOOL     xMBPortSerialPutByte( CHAR ucByte );
+
+/* ----------------------- Timers functions ---------------------------------*/
+BOOL            xMBPortTimersInit( USHORT usTimeOut50us );
+
+void            xMBPortTimersClose( void );
+
+INLINE void     vMBPortTimersEnable( void );
+
+INLINE void     vMBPortTimersDisable( void );
+
+/* ----------------------- Callback for the protocol stack ------------------*/
+
+/*!
+ * \brief Callback function for the porting layer when a new byte is
+ *   available.
+ *
+ * Depending upon the mode this callback function is used by the RTU or
+ * ASCII transmission layers. In any case a call to xMBPortSerialGetByte()
+ * must immediately return a new character.
+ *
+ * \return <code>TRUE</code> if a event was posted to the queue because
+ *   a new byte was received. The port implementation should wake up the
+ *   tasks which are currently blocked on the eventqueue.
+ */
+extern          BOOL( *pxMBFrameCBByteReceived ) ( void );
+
+extern          BOOL( *pxMBFrameCBTransmitterEmpty ) ( void );
+
+extern          BOOL( *pxMBPortCBTimerExpired ) ( void );
+
+/* ----------------------- TCP port functions -------------------------------*/
+BOOL            xMBTCPPortInit( USHORT usTCPPort );
+
+void            vMBTCPPortClose( void );
+
+void            vMBTCPPortDisable( void );
+
+BOOL            xMBTCPPortGetRequest( UCHAR **ppucMBTCPFrame, USHORT * usTCPLength );
+
+BOOL            xMBTCPPortSendResponse( const UCHAR *pucMBTCPFrame, USHORT usTCPLength );
+
+#ifdef __cplusplus
+PR_END_EXTERN_C
+#endif
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbproto.h	Thu Apr 15 12:10:34 2010 +0000
@@ -0,0 +1,83 @@
+/* 
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * File: $Id: mbproto.h,v 1.14 2006/12/07 22:10:34 wolti Exp $
+ */
+
+#ifndef _MB_PROTO_H
+#define _MB_PROTO_H
+
+#ifdef __cplusplus
+PR_BEGIN_EXTERN_C
+#endif
+/* ----------------------- Defines ------------------------------------------*/
+#define MB_ADDRESS_BROADCAST    ( 0 )   /*! Modbus broadcast address. */
+#define MB_ADDRESS_MIN          ( 1 )   /*! Smallest possible slave address. */
+#define MB_ADDRESS_MAX          ( 247 ) /*! Biggest possible slave address. */
+#define MB_FUNC_NONE                          (  0 )
+#define MB_FUNC_READ_COILS                    (  1 )
+#define MB_FUNC_READ_DISCRETE_INPUTS          (  2 )
+#define MB_FUNC_WRITE_SINGLE_COIL             (  5 )
+#define MB_FUNC_WRITE_MULTIPLE_COILS          ( 15 )
+#define MB_FUNC_READ_HOLDING_REGISTER         (  3 )
+#define MB_FUNC_READ_INPUT_REGISTER           (  4 )
+#define MB_FUNC_WRITE_REGISTER                (  6 )
+#define MB_FUNC_WRITE_MULTIPLE_REGISTERS      ( 16 )
+#define MB_FUNC_READWRITE_MULTIPLE_REGISTERS  ( 23 )
+#define MB_FUNC_DIAG_READ_EXCEPTION           (  7 )
+#define MB_FUNC_DIAG_DIAGNOSTIC               (  8 )
+#define MB_FUNC_DIAG_GET_COM_EVENT_CNT        ( 11 )
+#define MB_FUNC_DIAG_GET_COM_EVENT_LOG        ( 12 )
+#define MB_FUNC_OTHER_REPORT_SLAVEID          ( 17 )
+#define MB_FUNC_ERROR                         ( 128 )
+/* ----------------------- Type definitions ---------------------------------*/
+    typedef enum
+{
+    MB_EX_NONE = 0x00,
+    MB_EX_ILLEGAL_FUNCTION = 0x01,
+    MB_EX_ILLEGAL_DATA_ADDRESS = 0x02,
+    MB_EX_ILLEGAL_DATA_VALUE = 0x03,
+    MB_EX_SLAVE_DEVICE_FAILURE = 0x04,
+    MB_EX_ACKNOWLEDGE = 0x05,
+    MB_EX_SLAVE_BUSY = 0x06,
+    MB_EX_MEMORY_PARITY_ERROR = 0x08,
+    MB_EX_GATEWAY_PATH_FAILED = 0x0A,
+    MB_EX_GATEWAY_TGT_FAILED = 0x0B
+} eMBException;
+
+typedef         eMBException( *pxMBFunctionHandler ) ( UCHAR * pucFrame, USHORT * pusLength );
+
+typedef struct
+{
+    UCHAR           ucFunctionCode;
+    pxMBFunctionHandler pxHandler;
+} xMBFunctionHandler;
+
+#ifdef __cplusplus
+PR_END_EXTERN_C
+#endif
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbrtu.cpp	Thu Apr 15 12:10:34 2010 +0000
@@ -0,0 +1,358 @@
+/* 
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * File: $Id: mbrtu.c,v 1.18 2007/09/12 10:15:56 wolti Exp $
+ */
+
+/* ----------------------- System includes ----------------------------------*/
+#include "stdlib.h"
+#include "string.h"
+
+/* ----------------------- Platform includes --------------------------------*/
+#include "port.h"
+
+/* ----------------------- Modbus includes ----------------------------------*/
+#include "mb.h"
+#include "mbrtu.h"
+#include "mbframe.h"
+
+#include "mbcrc.h"
+#include "mbport.h"
+
+/* ----------------------- Defines ------------------------------------------*/
+#define MB_SER_PDU_SIZE_MIN     4       /*!< Minimum size of a Modbus RTU frame. */
+#define MB_SER_PDU_SIZE_MAX     256     /*!< Maximum size of a Modbus RTU frame. */
+#define MB_SER_PDU_SIZE_CRC     2       /*!< Size of CRC field in PDU. */
+#define MB_SER_PDU_ADDR_OFF     0       /*!< Offset of slave address in Ser-PDU. */
+#define MB_SER_PDU_PDU_OFF      1       /*!< Offset of Modbus-PDU in Ser-PDU. */
+
+/* ----------------------- Type definitions ---------------------------------*/
+typedef enum
+{
+    STATE_RX_INIT,              /*!< Receiver is in initial state. */
+    STATE_RX_IDLE,              /*!< Receiver is in idle state. */
+    STATE_RX_RCV,               /*!< Frame is beeing received. */
+    STATE_RX_ERROR              /*!< If the frame is invalid. */
+} eMBRcvState;
+
+typedef enum
+{
+    STATE_TX_IDLE,              /*!< Transmitter is in idle state. */
+    STATE_TX_XMIT               /*!< Transmitter is in transfer state. */
+} eMBSndState;
+
+/* ----------------------- Static variables ---------------------------------*/
+static volatile eMBSndState eSndState;
+static volatile eMBRcvState eRcvState;
+
+volatile UCHAR  ucRTUBuf[MB_SER_PDU_SIZE_MAX];
+
+static volatile UCHAR *pucSndBufferCur;
+static volatile USHORT usSndBufferCount;
+
+static volatile USHORT usRcvBufferPos;
+
+/* ----------------------- Start implementation -----------------------------*/
+eMBErrorCode
+eMBRTUInit( UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity )
+{
+    eMBErrorCode    eStatus = MB_ENOERR;
+    ULONG           usTimerT35_50us;
+
+    ( void )ucSlaveAddress;
+    ENTER_CRITICAL_SECTION(  );
+
+    /* Modbus RTU uses 8 Databits. */
+    if( xMBPortSerialInit( ucPort, ulBaudRate, 8, eParity ) != TRUE )
+    {
+        eStatus = MB_EPORTERR;
+    }
+    else
+    {
+        /* If baudrate > 19200 then we should use the fixed timer values
+         * t35 = 1750us. Otherwise t35 must be 3.5 times the character time.
+         */
+        if( ulBaudRate > 19200 )
+        {
+            usTimerT35_50us = 35;       /* 1800us. */
+        }
+        else
+        {
+            /* The timer reload value for a character is given by:
+             *
+             * ChTimeValue = Ticks_per_1s / ( Baudrate / 11 )
+             *             = 11 * Ticks_per_1s / Baudrate
+             *             = 220000 / Baudrate
+             * The reload for t3.5 is 1.5 times this value and similary
+             * for t3.5.
+             */
+            usTimerT35_50us = ( 7UL * 220000UL ) / ( 2UL * ulBaudRate );
+        }
+        if( xMBPortTimersInit( ( USHORT ) usTimerT35_50us ) != TRUE )
+        {
+            eStatus = MB_EPORTERR;
+        }
+    }
+    EXIT_CRITICAL_SECTION(  );
+
+    return eStatus;
+}
+
+void
+eMBRTUStart( void )
+{
+    ENTER_CRITICAL_SECTION(  );
+    /* Initially the receiver is in the state STATE_RX_INIT. we start
+     * the timer and if no character is received within t3.5 we change
+     * to STATE_RX_IDLE. This makes sure that we delay startup of the
+     * modbus protocol stack until the bus is free.
+     */
+    eRcvState = STATE_RX_INIT;
+    vMBPortSerialEnable( TRUE, FALSE );
+    vMBPortTimersEnable(  );
+    EXIT_CRITICAL_SECTION(  );
+}
+
+void
+eMBRTUStop( void )
+{
+    ENTER_CRITICAL_SECTION(  );
+    vMBPortSerialEnable( FALSE, FALSE );
+    vMBPortTimersDisable(  );
+    EXIT_CRITICAL_SECTION(  );
+}
+
+eMBErrorCode
+eMBRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength )
+{
+    BOOL            xFrameReceived = FALSE;
+    eMBErrorCode    eStatus = MB_ENOERR;
+
+    ENTER_CRITICAL_SECTION(  );
+    assert( usRcvBufferPos < MB_SER_PDU_SIZE_MAX );
+        
+    /* Length and CRC check */
+    if( ( usRcvBufferPos >= MB_SER_PDU_SIZE_MIN )
+        && ( usMBCRC16( ( UCHAR * ) ucRTUBuf, usRcvBufferPos ) == 0 ) )
+    {
+        /* Save the address field. All frames are passed to the upper layer
+         * and the decision if a frame is used is done there.
+         */
+        *pucRcvAddress = ucRTUBuf[MB_SER_PDU_ADDR_OFF];
+
+        /* Total length of Modbus-PDU is Modbus-Serial-Line-PDU minus
+         * size of address field and CRC checksum.
+         */
+        *pusLength = ( USHORT )( usRcvBufferPos - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_CRC );
+
+        /* Return the start of the Modbus PDU to the caller. */
+        *pucFrame = ( UCHAR * ) & ucRTUBuf[MB_SER_PDU_PDU_OFF];
+        xFrameReceived = TRUE;
+        
+        // Added by Cam
+        // Now that the poll routine knows about the received frame, 
+        // clear the receive buffer position ready for the next frame received
+        usRcvBufferPos = 0;
+
+    }
+    else
+    {
+        eStatus = MB_EIO;
+    }
+
+    EXIT_CRITICAL_SECTION(  );
+    return eStatus;
+}
+
+eMBErrorCode
+eMBRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength )
+{
+    eMBErrorCode    eStatus = MB_ENOERR;
+    USHORT          usCRC16;
+
+    ENTER_CRITICAL_SECTION(  );
+
+    /* Check if the receiver is still in idle state. If not we where to
+     * slow with processing the received frame and the master sent another
+     * frame on the network. We have to abort sending the frame.
+     */
+    if( eRcvState == STATE_RX_IDLE )
+    {
+        /* First byte before the Modbus-PDU is the slave address. */
+        pucSndBufferCur = ( UCHAR * ) pucFrame - 1;
+        usSndBufferCount = 1;
+
+        /* Now copy the Modbus-PDU into the Modbus-Serial-Line-PDU. */
+        pucSndBufferCur[MB_SER_PDU_ADDR_OFF] = ucSlaveAddress;
+        usSndBufferCount += usLength;
+
+        /* Calculate CRC16 checksum for Modbus-Serial-Line-PDU. */
+        usCRC16 = usMBCRC16( ( UCHAR * ) pucSndBufferCur, usSndBufferCount );
+        ucRTUBuf[usSndBufferCount++] = ( UCHAR )( usCRC16 & 0xFF );
+        ucRTUBuf[usSndBufferCount++] = ( UCHAR )( usCRC16 >> 8 );
+
+        /* Activate the transmitter. */
+        eSndState = STATE_TX_XMIT;
+        vMBPortSerialEnable( FALSE, TRUE );
+    }
+    else
+    {
+        eStatus = MB_EIO;
+    }
+    EXIT_CRITICAL_SECTION(  );
+    return eStatus;
+}
+
+BOOL
+xMBRTUReceiveFSM( void )
+{
+    BOOL            xTaskNeedSwitch = FALSE;
+    UCHAR           ucByte;
+
+    assert( eSndState == STATE_TX_IDLE );
+
+    /* Always read the character. */
+    ( void )xMBPortSerialGetByte( ( CHAR * ) & ucByte );
+
+    switch ( eRcvState )
+    {
+        /* If we have received a character in the init state we have to
+         * wait until the frame is finished.
+         */
+    case STATE_RX_INIT:
+        vMBPortTimersEnable(  );
+        break;
+
+        /* In the error state we wait until all characters in the
+         * damaged frame are transmitted.
+         */
+    case STATE_RX_ERROR:
+        vMBPortTimersEnable(  );
+        break;
+
+        /* In the idle state we wait for a new character. If a character
+         * is received the t1.5 and t3.5 timers are started and the
+         * receiver is in the state STATE_RX_RECEIVE.
+         */
+    case STATE_RX_IDLE:
+        ucRTUBuf[usRcvBufferPos++] = ucByte;
+        eRcvState = STATE_RX_RCV;
+
+        /* Enable t3.5 timers. */
+        vMBPortTimersEnable(  );
+        break;
+
+        /* We are currently receiving a frame. Reset the timer after
+         * every character received. If more than the maximum possible
+         * number of bytes in a modbus frame is received the frame is
+         * ignored.
+         */
+    case STATE_RX_RCV:
+        if( usRcvBufferPos < MB_SER_PDU_SIZE_MAX )
+        {
+            ucRTUBuf[usRcvBufferPos++] = ucByte;
+        }
+        else
+        {
+            eRcvState = STATE_RX_ERROR;
+        }
+        vMBPortTimersEnable(  );
+        break;
+    }
+    return xTaskNeedSwitch;
+}
+
+BOOL
+xMBRTUTransmitFSM( void )
+{
+    BOOL            xNeedPoll = FALSE;
+
+    assert( eRcvState == STATE_RX_IDLE );
+    switch ( eSndState )
+    {
+        /* We should not get a transmitter event if the transmitter is in
+         * idle state.  */
+    case STATE_TX_IDLE:
+        /* enable receiver/disable transmitter. */
+        vMBPortSerialEnable( TRUE, FALSE );
+        break;
+
+    case STATE_TX_XMIT:
+        /* check if we are finished. */
+        if( usSndBufferCount != 0 )
+        {
+            xMBPortSerialPutByte( ( CHAR )*pucSndBufferCur );
+            pucSndBufferCur++;  /* next byte in sendbuffer. */
+            usSndBufferCount--;
+        }
+        else
+        {
+            xNeedPoll = xMBPortEventPost( EV_FRAME_SENT );
+            /* Disable transmitter. This prevents another transmit buffer
+             * empty interrupt. */
+            vMBPortSerialEnable( TRUE, FALSE );
+            eSndState = STATE_TX_IDLE;
+        }
+        break;
+    }
+
+    return xNeedPoll;
+}
+
+BOOL
+xMBRTUTimerT35Expired( void )
+{
+    BOOL    xNeedPoll = FALSE;
+
+    switch ( eRcvState )
+    {
+        /* Timer t35 expired. Startup phase is finished. */
+    case STATE_RX_INIT:
+        xNeedPoll = xMBPortEventPost( EV_READY );
+        break;
+
+        /* A frame was received and t35 expired. Notify the listener that
+         * a new frame was received. */
+    case STATE_RX_RCV:
+        xNeedPoll = xMBPortEventPost( EV_FRAME_RECEIVED );
+        break;
+
+        /* An error occured while receiving the frame. */
+    case STATE_RX_ERROR:
+        break;
+
+        /* Function called in an illegal state. */
+    default:
+        assert( ( eRcvState == STATE_RX_INIT ) ||
+                ( eRcvState == STATE_RX_RCV ) || ( eRcvState == STATE_RX_ERROR ) );
+    }
+
+    vMBPortTimersDisable(  );
+    eRcvState = STATE_RX_IDLE;
+
+    return xNeedPoll;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbrtu.h	Thu Apr 15 12:10:34 2010 +0000
@@ -0,0 +1,51 @@
+/* 
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * File: $Id: mbrtu.h,v 1.9 2006/12/07 22:10:34 wolti Exp $
+ */
+
+#ifndef _MB_RTU_H
+#define _MB_RTU_H
+
+#ifdef __cplusplus
+PR_BEGIN_EXTERN_C
+#endif
+    eMBErrorCode eMBRTUInit( UCHAR slaveAddress, UCHAR ucPort, ULONG ulBaudRate,
+                             eMBParity eParity );
+void            eMBRTUStart( void );
+void            eMBRTUStop( void );
+eMBErrorCode    eMBRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength );
+eMBErrorCode    eMBRTUSend( UCHAR slaveAddress, const UCHAR * pucFrame, USHORT usLength );
+BOOL            xMBRTUReceiveFSM( void );
+BOOL            xMBRTUTransmitFSM( void );
+BOOL            xMBRTUTimerT15Expired( void );
+BOOL            xMBRTUTimerT35Expired( void );
+
+#ifdef __cplusplus
+PR_END_EXTERN_C
+#endif
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbutils.cpp	Thu Apr 15 12:10:34 2010 +0000
@@ -0,0 +1,141 @@
+/* 
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * File: $Id: mbutils.c,v 1.6 2007/02/18 23:49:07 wolti Exp $
+ */
+
+/* ----------------------- System includes ----------------------------------*/
+#include "stdlib.h"
+#include "string.h"
+
+/* ----------------------- Platform includes --------------------------------*/
+#include "port.h"
+
+/* ----------------------- Modbus includes ----------------------------------*/
+#include "mb.h"
+#include "mbproto.h"
+
+/* ----------------------- Defines ------------------------------------------*/
+#define BITS_UCHAR      8U
+
+/* ----------------------- Start implementation -----------------------------*/
+void
+xMBUtilSetBits( UCHAR * ucByteBuf, USHORT usBitOffset, UCHAR ucNBits,
+                UCHAR ucValue )
+{
+    USHORT          usWordBuf;
+    USHORT          usMask;
+    USHORT          usByteOffset;
+    USHORT          usNPreBits;
+    USHORT          usValue = ucValue;
+
+    assert( ucNBits <= 8 );
+    assert( ( size_t )BITS_UCHAR == sizeof( UCHAR ) * 8 );
+
+    /* Calculate byte offset for first byte containing the bit values starting
+     * at usBitOffset. */
+    usByteOffset = ( USHORT )( ( usBitOffset ) / BITS_UCHAR );
+
+    /* How many bits precede our bits to set. */
+    usNPreBits = ( USHORT )( usBitOffset - usByteOffset * BITS_UCHAR );
+
+    /* Move bit field into position over bits to set */
+    usValue <<= usNPreBits;
+
+    /* Prepare a mask for setting the new bits. */
+    usMask = ( USHORT )( ( 1 << ( USHORT ) ucNBits ) - 1 );
+    usMask <<= usBitOffset - usByteOffset * BITS_UCHAR;
+
+    /* copy bits into temporary storage. */
+    usWordBuf = ucByteBuf[usByteOffset];
+    usWordBuf |= ucByteBuf[usByteOffset + 1] << BITS_UCHAR;
+
+    /* Zero out bit field bits and then or value bits into them. */
+    usWordBuf = ( USHORT )( ( usWordBuf & ( ~usMask ) ) | usValue );
+
+    /* move bits back into storage */
+    ucByteBuf[usByteOffset] = ( UCHAR )( usWordBuf & 0xFF );
+    ucByteBuf[usByteOffset + 1] = ( UCHAR )( usWordBuf >> BITS_UCHAR );
+}
+
+UCHAR
+xMBUtilGetBits( UCHAR * ucByteBuf, USHORT usBitOffset, UCHAR ucNBits )
+{
+    USHORT          usWordBuf;
+    USHORT          usMask;
+    USHORT          usByteOffset;
+    USHORT          usNPreBits;
+
+    /* Calculate byte offset for first byte containing the bit values starting
+     * at usBitOffset. */
+    usByteOffset = ( USHORT )( ( usBitOffset ) / BITS_UCHAR );
+
+    /* How many bits precede our bits to set. */
+    usNPreBits = ( USHORT )( usBitOffset - usByteOffset * BITS_UCHAR );
+
+    /* Prepare a mask for setting the new bits. */
+    usMask = ( USHORT )( ( 1 << ( USHORT ) ucNBits ) - 1 );
+
+    /* copy bits into temporary storage. */
+    usWordBuf = ucByteBuf[usByteOffset];
+    usWordBuf |= ucByteBuf[usByteOffset + 1] << BITS_UCHAR;
+
+    /* throw away unneeded bits. */
+    usWordBuf >>= usNPreBits;
+
+    /* mask away bits above the requested bitfield. */
+    usWordBuf &= usMask;
+
+    return ( UCHAR ) usWordBuf;
+}
+
+eMBException
+prveMBError2Exception( eMBErrorCode eErrorCode )
+{
+    eMBException    eStatus;
+
+    switch ( eErrorCode )
+    {
+        case MB_ENOERR:
+            eStatus = MB_EX_NONE;
+            break;
+
+        case MB_ENOREG:
+            eStatus = MB_EX_ILLEGAL_DATA_ADDRESS;
+            break;
+
+        case MB_ETIMEDOUT:
+            eStatus = MB_EX_SLAVE_BUSY;
+            break;
+
+        default:
+            eStatus = MB_EX_SLAVE_DEVICE_FAILURE;
+            break;
+    }
+
+    return eStatus;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbutils.h	Thu Apr 15 12:10:34 2010 +0000
@@ -0,0 +1,108 @@
+/* 
+ * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
+ * Copyright (c) 2006 Christian Walter <wolti@sil.at>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * File: $Id: mbutils.h,v 1.5 2006/12/07 22:10:34 wolti Exp $
+ */
+
+#ifndef _MB_UTILS_H
+#define _MB_UTILS_H
+
+#ifdef __cplusplus
+PR_BEGIN_EXTERN_C
+#endif
+/*! \defgroup modbus_utils Utilities
+ *
+ * This module contains some utility functions which can be used by
+ * the application. It includes some special functions for working with
+ * bitfields backed by a character array buffer.
+ *
+ */
+/*! \addtogroup modbus_utils
+ *  @{
+ */
+/*! \brief Function to set bits in a byte buffer.
+ *
+ * This function allows the efficient use of an array to implement bitfields.
+ * The array used for storing the bits must always be a multiple of two
+ * bytes. Up to eight bits can be set or cleared in one operation.
+ *
+ * \param ucByteBuf A buffer where the bit values are stored. Must be a
+ *   multiple of 2 bytes. No length checking is performed and if
+ *   usBitOffset / 8 is greater than the size of the buffer memory contents
+ *   is overwritten.
+ * \param usBitOffset The starting address of the bits to set. The first
+ *   bit has the offset 0.
+ * \param ucNBits Number of bits to modify. The value must always be smaller
+ *   than 8.
+ * \param ucValues Thew new values for the bits. The value for the first bit
+ *   starting at <code>usBitOffset</code> is the LSB of the value
+ *   <code>ucValues</code>
+ *
+ * \code
+ * ucBits[2] = {0, 0};
+ *
+ * // Set bit 4 to 1 (read: set 1 bit starting at bit offset 4 to value 1)
+ * xMBUtilSetBits( ucBits, 4, 1, 1 );
+ *
+ * // Set bit 7 to 1 and bit 8 to 0.
+ * xMBUtilSetBits( ucBits, 7, 2, 0x01 );
+ *
+ * // Set bits 8 - 11 to 0x05 and bits 12 - 15 to 0x0A;
+ * xMBUtilSetBits( ucBits, 8, 8, 0x5A);
+ * \endcode
+ */
+void            xMBUtilSetBits( UCHAR * ucByteBuf, USHORT usBitOffset,
+                                UCHAR ucNBits, UCHAR ucValues );
+
+/*! \brief Function to read bits in a byte buffer.
+ *
+ * This function is used to extract up bit values from an array. Up to eight
+ * bit values can be extracted in one step.
+ *
+ * \param ucByteBuf A buffer where the bit values are stored.
+ * \param usBitOffset The starting address of the bits to set. The first
+ *   bit has the offset 0.
+ * \param ucNBits Number of bits to modify. The value must always be smaller
+ *   than 8.
+ *
+ * \code
+ * UCHAR ucBits[2] = {0, 0};
+ * UCHAR ucResult;
+ *
+ * // Extract the bits 3 - 10.
+ * ucResult = xMBUtilGetBits( ucBits, 3, 8 );
+ * \endcode
+ */
+UCHAR           xMBUtilGetBits( UCHAR * ucByteBuf, USHORT usBitOffset,
+                                UCHAR ucNBits );
+
+/*! @} */
+
+#ifdef __cplusplus
+PR_END_EXTERN_C
+#endif
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/port.h	Thu Apr 15 12:10:34 2010 +0000
@@ -0,0 +1,54 @@
+/*
+ * FreeModbus Libary: BARE Port
+ * Copyright (C) 2006 Christian Walter <wolti@sil.at>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * File: $Id: port.h,v 1.1 2006/08/22 21:35:13 wolti Exp $
+ */
+
+#ifndef _PORT_H
+#define _PORT_H
+
+#include <assert.h>
+#include <inttypes.h>
+
+#define INLINE                      //inline
+#define PR_BEGIN_EXTERN_C           //extern "C" {
+#define PR_END_EXTERN_C             //}
+
+#define ENTER_CRITICAL_SECTION( )   
+#define EXIT_CRITICAL_SECTION( )    
+
+typedef uint8_t BOOL;
+
+typedef unsigned char UCHAR;
+typedef char CHAR;
+
+typedef uint16_t USHORT;
+typedef int16_t SHORT;
+
+typedef uint32_t ULONG;
+typedef int32_t LONG;
+
+#ifndef TRUE
+#define TRUE            1
+#endif
+
+#ifndef FALSE
+#define FALSE           0
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/portevent.cpp	Thu Apr 15 12:10:34 2010 +0000
@@ -0,0 +1,58 @@
+/*
+ * FreeModbus Libary: BARE Port
+ * Copyright (C) 2006 Christian Walter <wolti@sil.at>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * File: $Id: portevent.c,v 1.1 2006/08/22 21:35:13 wolti Exp $
+ */
+
+/* ----------------------- Modbus includes ----------------------------------*/
+#include "mb.h"
+#include "mbport.h"
+
+/* ----------------------- Variables ----------------------------------------*/
+static eMBEventType eQueuedEvent;
+static BOOL         xEventInQueue;
+
+/* ----------------------- Start implementation -----------------------------*/
+BOOL
+xMBPortEventInit( void )
+{
+    xEventInQueue = FALSE;
+    return TRUE;
+}
+
+BOOL
+xMBPortEventPost( eMBEventType eEvent )
+{
+    xEventInQueue = TRUE;
+    eQueuedEvent = eEvent;
+    return TRUE;
+}
+
+BOOL
+xMBPortEventGet( eMBEventType * eEvent )
+{
+    BOOL    xEventHappened = FALSE;
+
+    if( xEventInQueue )
+    {
+        *eEvent = eQueuedEvent;
+        xEventInQueue = FALSE;
+        xEventHappened = TRUE;
+    }
+    return xEventHappened;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/portserial.cpp	Thu Apr 15 12:10:34 2010 +0000
@@ -0,0 +1,125 @@
+/*
+ * FreeModbus Libary: BARE Port
+ * Copyright (C) 2006 Christian Walter <wolti@sil.at>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * File: $Id: portserial.c,v 1.1 2006/08/22 21:35:13 wolti Exp $
+ */
+
+/* ----------------------- System includes ----------------------------------*/
+#include "mbed.h"                   // Cam
+
+/* ----------------------- Platform includes --------------------------------*/
+#include "port.h"
+
+/* ----------------------- Modbus includes ----------------------------------*/
+#include "mb.h"
+#include "mbport.h"
+
+
+/* ----------------------- static functions ---------------------------------*/
+static void prvvUARTTxReadyISR( void );
+static void prvvUARTRxISR( void );
+static void prvvUARTISR( void );
+
+/* ----------------------- System Variables ---------------------------------*/
+Serial pc(USBTX, USBRX);            // Cam - mbed USB serial port
+
+Ticker simISR;                      // Cam - mbed ticker
+                                    // we don't have the TX buff empty interrupt, so
+                                    // we just interrupt every 1 mSec and read RX & TX
+                                    // status to simulate the proper ISRs.
+
+static BOOL RxEnable, TxEnable;     // Cam - keep a static copy of the RxEnable and TxEnable
+                                    // status for the simulated ISR (ticker)
+
+
+/* ----------------------- Start implementation -----------------------------*/
+// Cam - This is called every 1mS to simulate Rx character received ISR and
+// Tx buffer empty ISR.
+static void
+prvvUARTISR( void )
+{
+    if (TxEnable)
+        if(pc.writeable())
+            prvvUARTTxReadyISR();
+            
+    if (RxEnable)
+        if(pc.readable())
+            prvvUARTRxISR();          
+}
+
+void
+vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
+{
+    /* If xRXEnable enable serial receive interrupts. If xTxENable enable
+     * transmitter empty interrupts.
+     */
+    RxEnable = xRxEnable;
+    TxEnable = xTxEnable;
+}
+
+BOOL
+xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
+{
+    simISR.attach_us(&prvvUARTISR,1000);    // Cam - attach prvvUARTISR to a 1mS ticker to simulate serial interrupt behaviour
+                                            // 1mS is just short of a character time at 9600 bps, so quick enough to pick
+                                            // up status on a character by character basis.
+    return TRUE;
+}
+
+BOOL
+xMBPortSerialPutByte( CHAR ucByte )
+{
+    /* Put a byte in the UARTs transmit buffer. This function is called
+     * by the protocol stack if pxMBFrameCBTransmitterEmpty( ) has been
+     * called. */
+    pc.putc( ucByte);
+    return TRUE;
+}
+
+BOOL
+xMBPortSerialGetByte( CHAR * pucByte )
+{
+    /* Return the byte in the UARTs receive buffer. This function is called
+     * by the protocol stack after pxMBFrameCBByteReceived( ) has been called.
+     */
+    * pucByte = pc.getc();
+    return TRUE;
+}
+
+/* Create an interrupt handler for the transmit buffer empty interrupt
+ * (or an equivalent) for your target processor. This function should then
+ * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that
+ * a new character can be sent. The protocol stack will then call 
+ * xMBPortSerialPutByte( ) to send the character.
+ */
+static void prvvUARTTxReadyISR( void )
+{
+    pxMBFrameCBTransmitterEmpty(  );
+}
+
+/* Create an interrupt handler for the receive interrupt for your target
+ * processor. This function should then call pxMBFrameCBByteReceived( ). The
+ * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
+ * character.
+ */
+static void prvvUARTRxISR( void )
+{
+    pxMBFrameCBByteReceived(  );
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/porttimer.cpp	Thu Apr 15 12:10:34 2010 +0000
@@ -0,0 +1,78 @@
+/*
+ * FreeModbus Libary: BARE Port
+ * Copyright (C) 2006 Christian Walter <wolti@sil.at>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * File: $Id: porttimer.c,v 1.1 2006/08/22 21:35:13 wolti Exp $
+ */
+
+/* ----------------------- System includes ----------------------------------*/
+#include "mbed.h"           // Cam
+
+/* ----------------------- Platform includes --------------------------------*/
+#include "port.h"
+
+/* ----------------------- Modbus includes ----------------------------------*/
+#include "mb.h"
+#include "mbport.h"
+
+/* ----------------------- static functions ---------------------------------*/
+static void prvvTIMERExpiredISR( void );
+
+/* ----------------------- System Variables ---------------------------------*/
+Timeout toMBUS;             // Cam - mbed timeout
+static ULONG usInterval;    // Cam - timeout interval in microseconds 
+
+/* ----------------------- Start implementation -----------------------------*/
+BOOL
+xMBPortTimersInit( USHORT usTim1Timerout50us )
+{
+    usInterval = 50 * usTim1Timerout50us;
+    return TRUE;
+}
+
+
+/*inline*/ void
+vMBPortTimersEnable(  )
+{
+    /* Enable the timer with the timeout passed to xMBPortTimersInit( ) */
+    
+    // Cam - firstly detach from any existing timeout
+    toMBUS.detach();
+    // Cam - now attach the timeout to the prvvTIMERExpiredISR routine    
+    toMBUS.attach_us(&prvvTIMERExpiredISR, usInterval); 
+}
+
+/*inline*/ void
+vMBPortTimersDisable(  )
+{
+    /* Disable any pending timers. */
+    
+    // Cam - disable further interrupts by detaching
+    toMBUS.detach();
+}
+
+/* Create an ISR which is called whenever the timer has expired. This function
+ * must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that
+ * the timer has expired.
+ */
+static void prvvTIMERExpiredISR( void )
+{
+    ( void )pxMBPortCBTimerExpired(  );
+    // Cam - disable further interrupts by detaching
+    toMBUS.detach(); 
+}
+