view modbus
This commit is contained in:
+1
-30
@@ -388,36 +388,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
|
||||
# CONFIG_PKG_USING_KAWAII_MQTT is not set
|
||||
# CONFIG_PKG_USING_BC28_MQTT is not set
|
||||
# CONFIG_PKG_USING_WEBTERMINAL is not set
|
||||
CONFIG_PKG_USING_FREEMODBUS=y
|
||||
CONFIG_PKG_FREEMODBUS_PATH="/packages/iot/freemodbus"
|
||||
# CONFIG_PKG_MODBUS_MASTER is not set
|
||||
CONFIG_PKG_MODBUS_SLAVE=y
|
||||
|
||||
#
|
||||
# advanced configuration
|
||||
#
|
||||
CONFIG_RT_S_DISCRETE_INPUT_START=0
|
||||
CONFIG_RT_S_DISCRETE_INPUT_NDISCRETES=16
|
||||
CONFIG_RT_S_COIL_START=0
|
||||
CONFIG_RT_S_COIL_NCOILS=64
|
||||
CONFIG_RT_S_REG_INPUT_START=0
|
||||
CONFIG_RT_S_REG_INPUT_NREGS=100
|
||||
CONFIG_RT_S_REG_HOLDING_START=0
|
||||
CONFIG_RT_S_REG_HOLDING_NREGS=100
|
||||
CONFIG_RT_S_HD_RESERVE=0
|
||||
CONFIG_RT_S_IN_RESERVE=0
|
||||
CONFIG_RT_S_CO_RESERVE=0
|
||||
CONFIG_RT_S_DI_RESERVE=0
|
||||
# end of advanced configuration
|
||||
|
||||
CONFIG_PKG_MODBUS_SLAVE_RTU=y
|
||||
# CONFIG_PKG_MODBUS_SLAVE_ASCII is not set
|
||||
# CONFIG_PKG_MODBUS_SLAVE_TCP is not set
|
||||
# CONFIG_RT_MODBUS_SLAVE_USE_CONTROL_PIN is not set
|
||||
# CONFIG_PKG_MODBUS_SLAVE_SAMPLE is not set
|
||||
# CONFIG_PKG_USING_FREEMODBUS_V160 is not set
|
||||
CONFIG_PKG_USING_FREEMODBUS_LATEST_VERSION=y
|
||||
CONFIG_PKG_FREEMODBUS_VER="latest"
|
||||
# CONFIG_PKG_USING_FREEMODBUS is not set
|
||||
# CONFIG_PKG_USING_NANOPB is not set
|
||||
# CONFIG_PKG_USING_WIFI_HOST_DRIVER is not set
|
||||
# CONFIG_PKG_USING_ESP_HOSTED is not set
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
from building import *
|
||||
import os
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c')
|
||||
|
||||
path = [cwd]
|
||||
|
||||
group = DefineGroup('Applications/mb', src, depend = [''], CPPPATH = path)
|
||||
|
||||
list = os.listdir(cwd)
|
||||
for item in list:
|
||||
if os.path.isfile(os.path.join(cwd, item, 'SConscript')):
|
||||
group = group + SConscript(os.path.join(item, 'SConscript'))
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,264 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
|
||||
#include "mb.h"
|
||||
#include "mbfunc.h"
|
||||
#include "mbport.h"
|
||||
#include "mbrtu.h"
|
||||
|
||||
|
||||
static rt_uint8_t ucMBAddress;
|
||||
|
||||
static enum {
|
||||
STATE_ENABLED,
|
||||
STATE_DISABLED,
|
||||
STATE_NOT_INITIALIZED
|
||||
} eMBState = STATE_NOT_INITIALIZED;
|
||||
|
||||
|
||||
static peMBFrameSend peMBFrameSendCur;
|
||||
static pvMBFrameStart pvMBFrameStartCur;
|
||||
static pvMBFrameStop pvMBFrameStopCur;
|
||||
static peMBFrameReceive peMBFrameReceiveCur;
|
||||
static pvMBFrameClose pvMBFrameCloseCur;
|
||||
|
||||
rt_uint8_t( *pxMBFrameCBByteReceived ) ( void );
|
||||
rt_uint8_t( *pxMBFrameCBTransmitterEmpty ) ( void );
|
||||
rt_uint8_t( *pxMBPortCBTimerExpired ) ( void );
|
||||
|
||||
rt_uint8_t( *pxMBFrameCBReceiveFSMCur ) ( void );
|
||||
rt_uint8_t( *pxMBFrameCBTransmitFSMCur ) ( void );
|
||||
|
||||
#define MB_FUNC_HANDLERS_MAX (16)
|
||||
|
||||
static xMBFunctionHandler xFuncHandlers[MB_FUNC_HANDLERS_MAX] = {
|
||||
{MB_FUNC_OTHER_REPORT_SLAVEID, eMBFuncReportSlaveID},
|
||||
{MB_FUNC_READ_INPUT_REGISTER, eMBFuncReadInputRegister},
|
||||
{MB_FUNC_READ_HOLDING_REGISTER, eMBFuncReadHoldingRegister},
|
||||
{MB_FUNC_WRITE_MULTIPLE_REGISTERS, eMBFuncWriteMultipleHoldingRegister},
|
||||
{MB_FUNC_WRITE_REGISTER, eMBFuncWriteHoldingRegister},
|
||||
{MB_FUNC_READWRITE_MULTIPLE_REGISTERS, eMBFuncReadWriteMultipleHoldingRegister},
|
||||
{MB_FUNC_READ_COILS, eMBFuncReadCoils},
|
||||
{MB_FUNC_WRITE_SINGLE_COIL, eMBFuncWriteCoil},
|
||||
{MB_FUNC_WRITE_MULTIPLE_COILS, eMBFuncWriteMultipleCoils},
|
||||
{MB_FUNC_READ_DISCRETE_INPUTS, eMBFuncReadDiscreteInputs},
|
||||
};
|
||||
|
||||
eMBErrorCode eMBInit(rt_uint8_t ucSlaveAddress, rt_uint8_t ucPort, rt_uint32_t ulBaudRate, eMBParity eParity )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
|
||||
if((ucSlaveAddress == MB_ADDRESS_BROADCAST) ||
|
||||
(ucSlaveAddress < MB_ADDRESS_MIN)||( ucSlaveAddress > MB_ADDRESS_MAX)) {
|
||||
eStatus = MB_EINVAL;
|
||||
} else {
|
||||
ucMBAddress = ucSlaveAddress;
|
||||
|
||||
pvMBFrameStartCur = eMBRTUStart;
|
||||
pvMBFrameStopCur = eMBRTUStop;
|
||||
peMBFrameSendCur = eMBRTUSend;
|
||||
peMBFrameReceiveCur = eMBRTUReceive;
|
||||
pvMBFrameCloseCur = NULL;
|
||||
pxMBFrameCBByteReceived = xMBRTUReceiveFSM;
|
||||
pxMBFrameCBTransmitterEmpty = xMBRTUTransmitFSM;
|
||||
pxMBPortCBTimerExpired = xMBRTUTimerT35Expired;
|
||||
|
||||
eStatus = eMBRTUInit( ucMBAddress, ucPort, ulBaudRate, eParity );
|
||||
if( eStatus == MB_ENOERR ) {
|
||||
if(!xMBPortEventInit()) {
|
||||
/* port dependent event module initalization failed. */
|
||||
eStatus = MB_EPORTERR;
|
||||
} else {
|
||||
eMBState = STATE_DISABLED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
eMBErrorCode eMBRegisterCB( rt_uint8_t ucFunctionCode, pxMBFunctionHandler pxHandler )
|
||||
{
|
||||
int i;
|
||||
eMBErrorCode eStatus;
|
||||
|
||||
if( ( 0 < ucFunctionCode ) && ( ucFunctionCode <= 127 ) ) {
|
||||
EnterCriticalSection();
|
||||
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;
|
||||
}
|
||||
ExitCriticalSection();
|
||||
}
|
||||
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 rt_uint8_t *ucMBFrame;
|
||||
static rt_uint8_t ucRcvAddress;
|
||||
static rt_uint8_t ucFunctionCode;
|
||||
static rt_uint16_t 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++] = ( rt_uint8_t )( ucFunctionCode | MB_FUNC_ERROR );
|
||||
ucMBFrame[usLength++] = eException;
|
||||
}
|
||||
eStatus = peMBFrameSendCur( ucMBAddress, ucMBFrame, usLength );
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_FRAME_SENT:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return MB_ENOERR;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,93 +1,16 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.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__
|
||||
|
||||
#ifndef _MB_H
|
||||
#define _MB_H
|
||||
|
||||
#include "port.h"
|
||||
#include <rtthread.h>
|
||||
#include <assert.h>
|
||||
//#include <inttypes.h>
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
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.
|
||||
@@ -100,8 +23,7 @@ extern "C" {
|
||||
* \see eMBRegHoldingCB( ), eMBRegCoilsCB( ), eMBRegDiscreteCB( ) and
|
||||
* eMBRegInputCB( ).
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
typedef enum {
|
||||
MB_REG_READ, /*!< Read register values and pass to protocol stack. */
|
||||
MB_REG_WRITE /*!< Update register values. */
|
||||
} eMBRegisterMode;
|
||||
@@ -109,8 +31,7 @@ typedef enum
|
||||
/*! \ingroup modbus
|
||||
* \brief Errorcodes used by all function in the protocol stack.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
typedef enum {
|
||||
MB_ENOERR, /*!< no error. */
|
||||
MB_ENOREG, /*!< illegal register address. */
|
||||
MB_EINVAL, /*!< illegal argument. */
|
||||
@@ -121,8 +42,67 @@ typedef enum
|
||||
MB_ETIMEDOUT /*!< timeout error occurred. */
|
||||
} eMBErrorCode;
|
||||
|
||||
typedef enum {
|
||||
EV_READY = 1<<0, /*!< Startup finished. */
|
||||
EV_FRAME_RECEIVED = 1<<1, /*!< Frame received. */
|
||||
EV_EXECUTE = 1<<2, /*!< Execute function. */
|
||||
EV_FRAME_SENT = 1<<3 /*!< 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;
|
||||
|
||||
#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 )
|
||||
|
||||
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 ) ( rt_uint8_t * pucFrame, rt_uint16_t * pusLength );
|
||||
|
||||
typedef struct {
|
||||
rt_uint8_t ucFunctionCode;
|
||||
pxMBFunctionHandler pxHandler;
|
||||
} xMBFunctionHandler;
|
||||
|
||||
|
||||
/* ----------------------- Function prototypes ------------------------------*/
|
||||
/*! \ingroup modbus
|
||||
* \brief Initialize the Modbus protocol stack.
|
||||
*
|
||||
@@ -148,24 +128,8 @@ typedef enum
|
||||
* 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 );
|
||||
eMBErrorCode eMBInit(rt_uint8_t ucSlaveAddress, rt_uint8_t ucPort,
|
||||
rt_uint32_t ulBaudRate, eMBParity eParity );
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief Release resources used by the protocol stack.
|
||||
@@ -181,7 +145,7 @@ eMBErrorCode eMBTCPInit( USHORT usTCPPort );
|
||||
* If the protocol stack is not in the disabled state it returns
|
||||
* eMBErrorCode::MB_EILLSTATE.
|
||||
*/
|
||||
eMBErrorCode eMBClose( void );
|
||||
eMBErrorCode eMBClose( void );
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief Enable the Modbus protocol stack.
|
||||
@@ -193,7 +157,7 @@ eMBErrorCode eMBClose( void );
|
||||
* eMBErrorCode::MB_ENOERR. If it was not in the disabled state it
|
||||
* return eMBErrorCode::MB_EILLSTATE.
|
||||
*/
|
||||
eMBErrorCode eMBEnable( void );
|
||||
eMBErrorCode eMBEnable( void );
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief Disable the Modbus protocol stack.
|
||||
@@ -204,7 +168,7 @@ eMBErrorCode eMBEnable( void );
|
||||
* eMBErrorCode::MB_ENOERR. If it was not in the enabled state it returns
|
||||
* eMBErrorCode::MB_EILLSTATE.
|
||||
*/
|
||||
eMBErrorCode eMBDisable( void );
|
||||
eMBErrorCode eMBDisable( void );
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief The main pooling loop of the Modbus protocol stack.
|
||||
@@ -218,7 +182,7 @@ eMBErrorCode eMBDisable( void );
|
||||
* returns eMBErrorCode::MB_EILLSTATE. Otherwise it returns
|
||||
* eMBErrorCode::MB_ENOERR.
|
||||
*/
|
||||
eMBErrorCode eMBPoll( void );
|
||||
eMBErrorCode eMBPoll( void );
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief Configure the slave id of the device.
|
||||
@@ -238,9 +202,8 @@ eMBErrorCode eMBPoll( void );
|
||||
* 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 );
|
||||
eMBErrorCode eMBSetSlaveID( rt_uint8_t ucSlaveID, rt_uint8_t xIsRunning,
|
||||
rt_uint8_t const *pucAdditional, rt_uint16_t usAdditionalLen );
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief Registers a callback handler for a given function code.
|
||||
@@ -262,8 +225,7 @@ eMBErrorCode eMBSetSlaveID( UCHAR ucSlaveID, BOOL xIsRunning,
|
||||
* 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 );
|
||||
eMBErrorCode eMBRegisterCB( rt_uint8_t ucFunctionCode, pxMBFunctionHandler pxHandler );
|
||||
|
||||
/* ----------------------- Callback -----------------------------------------*/
|
||||
|
||||
@@ -309,8 +271,8 @@ eMBErrorCode eMBRegisterCB( UCHAR ucFunctionCode,
|
||||
* - 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 );
|
||||
eMBErrorCode eMBRegInputCB( rt_uint8_t * pucRegBuffer, rt_uint16_t usAddress,
|
||||
rt_uint16_t usNRegs );
|
||||
|
||||
/*! \ingroup modbus_registers
|
||||
* \brief Callback function used if a <em>Holding Register</em> value is
|
||||
@@ -344,8 +306,8 @@ eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress,
|
||||
* - 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 );
|
||||
eMBErrorCode eMBRegHoldingCB( rt_uint8_t * pucRegBuffer, rt_uint16_t usAddress,
|
||||
rt_uint16_t usNRegs, eMBRegisterMode eMode );
|
||||
|
||||
/*! \ingroup modbus_registers
|
||||
* \brief Callback function used if a <em>Coil Register</em> value is
|
||||
@@ -379,8 +341,8 @@ eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress,
|
||||
* - 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 );
|
||||
eMBErrorCode eMBRegCoilsCB( rt_uint8_t * pucRegBuffer, rt_uint16_t usAddress,
|
||||
rt_uint16_t usNCoils, eMBRegisterMode eMode );
|
||||
|
||||
/*! \ingroup modbus_registers
|
||||
* \brief Callback function used if a <em>Input Discrete Register</em> value is
|
||||
@@ -408,8 +370,50 @@ eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress,
|
||||
* - 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 );
|
||||
eMBErrorCode eMBRegDiscreteCB( rt_uint8_t * pucRegBuffer, rt_uint16_t usAddress,
|
||||
rt_uint16_t usNDiscrete );
|
||||
|
||||
/*!
|
||||
* 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>
|
||||
*/
|
||||
|
||||
#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. */
|
||||
|
||||
typedef void ( *pvMBFrameStart ) ( void );
|
||||
|
||||
typedef void ( *pvMBFrameStop ) ( void );
|
||||
|
||||
typedef eMBErrorCode( *peMBFrameReceive ) ( rt_uint8_t * pucRcvAddress,
|
||||
rt_uint8_t ** pucFrame, rt_uint16_t * pusLength );
|
||||
|
||||
typedef eMBErrorCode( *peMBFrameSend ) ( rt_uint8_t slaveAddress,
|
||||
const rt_uint8_t * pucFrame, rt_uint16_t usLength );
|
||||
|
||||
typedef void( *pvMBFrameClose ) ( void );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
@@ -1,37 +1,7 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.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"
|
||||
#include <rtthread.h>
|
||||
|
||||
static const UCHAR aucCRCHi[] = {
|
||||
static const rt_uint8_t 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,
|
||||
@@ -56,7 +26,7 @@ static const UCHAR aucCRCHi[] = {
|
||||
0x00, 0xC1, 0x81, 0x40
|
||||
};
|
||||
|
||||
static const UCHAR aucCRCLo[] = {
|
||||
static const rt_uint8_t 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,
|
||||
@@ -81,18 +51,20 @@ static const UCHAR aucCRCLo[] = {
|
||||
0x41, 0x81, 0x80, 0x40
|
||||
};
|
||||
|
||||
USHORT
|
||||
usMBCRC16( UCHAR * pucFrame, USHORT usLen )
|
||||
rt_uint16_t usMBCRC16( rt_uint8_t * pucFrame, rt_uint16_t usLen )
|
||||
{
|
||||
UCHAR ucCRCHi = 0xFF;
|
||||
UCHAR ucCRCLo = 0xFF;
|
||||
rt_uint8_t ucCRCHi = 0xFF;
|
||||
rt_uint8_t ucCRCLo = 0xFF;
|
||||
int iIndex;
|
||||
|
||||
while( usLen-- )
|
||||
{
|
||||
iIndex = ucCRCLo ^ *( pucFrame++ );
|
||||
ucCRCLo = ( UCHAR )( ucCRCHi ^ aucCRCHi[iIndex] );
|
||||
ucCRCLo = ( rt_uint8_t )( ucCRCHi ^ aucCRCHi[iIndex] );
|
||||
ucCRCHi = aucCRCLo[iIndex];
|
||||
}
|
||||
return ( USHORT )( ucCRCHi << 8 | ucCRCLo );
|
||||
return ( rt_uint16_t )( ucCRCHi << 8 | ucCRCLo );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
#ifndef __MB_CRC_H__
|
||||
#define __MB_CRC_H__
|
||||
|
||||
rt_uint16_t usMBCRC16( rt_uint8_t * pucFrame, rt_uint16_t usLen );
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
|
||||
#include "mb.h"
|
||||
#include "mbport.h"
|
||||
|
||||
static struct rt_event xSlaveOsEvent;
|
||||
|
||||
rt_uint8_t xMBPortEventInit( void )
|
||||
{
|
||||
rt_event_init(&xSlaveOsEvent,"slave event",RT_IPC_FLAG_PRIO);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
rt_uint8_t xMBPortEventPost( eMBEventType eEvent )
|
||||
{
|
||||
rt_event_send(&xSlaveOsEvent, eEvent);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
rt_uint8_t xMBPortEventGet( eMBEventType * eEvent )
|
||||
{
|
||||
rt_uint32_t recvedEvent;
|
||||
/* waiting forever OS event */
|
||||
rt_event_recv(&xSlaveOsEvent,
|
||||
EV_READY | EV_FRAME_RECEIVED | EV_EXECUTE | EV_FRAME_SENT,
|
||||
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER,
|
||||
&recvedEvent);
|
||||
switch (recvedEvent)
|
||||
{
|
||||
case EV_READY:
|
||||
*eEvent = EV_READY;
|
||||
break;
|
||||
case EV_FRAME_RECEIVED:
|
||||
*eEvent = EV_FRAME_RECEIVED;
|
||||
break;
|
||||
case EV_EXECUTE:
|
||||
*eEvent = EV_EXECUTE;
|
||||
break;
|
||||
case EV_FRAME_SENT:
|
||||
*eEvent = EV_FRAME_SENT;
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
|
||||
#ifndef __MB_FUNC_H__
|
||||
#define __MB_FUNC_H__
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "mb.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
eMBException eMBFuncReportSlaveID( rt_uint8_t * pucFrame, rt_uint16_t * usLen );
|
||||
|
||||
eMBException eMBFuncReadInputRegister( rt_uint8_t * pucFrame, rt_uint16_t * usLen );
|
||||
|
||||
eMBException eMBFuncReadHoldingRegister( rt_uint8_t * pucFrame, rt_uint16_t * usLen );
|
||||
|
||||
eMBException eMBFuncWriteHoldingRegister( rt_uint8_t * pucFrame, rt_uint16_t * usLen );
|
||||
|
||||
eMBException eMBFuncWriteMultipleHoldingRegister( rt_uint8_t * pucFrame, rt_uint16_t * usLen );
|
||||
|
||||
eMBException eMBFuncReadCoils( rt_uint8_t * pucFrame, rt_uint16_t * usLen );
|
||||
|
||||
eMBException eMBFuncWriteCoil( rt_uint8_t * pucFrame, rt_uint16_t * usLen );
|
||||
|
||||
eMBException eMBFuncWriteMultipleCoils( rt_uint8_t * pucFrame, rt_uint16_t * usLen );
|
||||
|
||||
eMBException eMBFuncReadDiscreteInputs( rt_uint8_t * pucFrame, rt_uint16_t * usLen );
|
||||
|
||||
eMBException eMBFuncReadWriteMultipleHoldingRegister( rt_uint8_t * pucFrame, rt_uint16_t * usLen );
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
+32
-80
@@ -1,47 +1,11 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.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"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* ----------------------- Platform includes --------------------------------*/
|
||||
#include "port.h"
|
||||
#include <rtthread.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 )
|
||||
@@ -58,32 +22,26 @@
|
||||
#define MB_PDU_FUNC_WRITE_MUL_SIZE_MIN ( 5 )
|
||||
#define MB_PDU_FUNC_WRITE_MUL_COILCNT_MAX ( 0x07B0 )
|
||||
|
||||
/* ----------------------- Static functions ---------------------------------*/
|
||||
eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
|
||||
eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
|
||||
#if MB_FUNC_READ_COILS_ENABLED > 0
|
||||
|
||||
eMBException
|
||||
eMBFuncReadCoils( UCHAR * pucFrame, USHORT * usLen )
|
||||
eMBException eMBFuncReadCoils( rt_uint8_t * pucFrame, rt_uint16_t * usLen )
|
||||
{
|
||||
USHORT usRegAddress;
|
||||
USHORT usCoilCount;
|
||||
UCHAR ucNBytes;
|
||||
UCHAR *pucFrameCur;
|
||||
rt_uint16_t usRegAddress;
|
||||
rt_uint16_t usCoilCount;
|
||||
rt_uint8_t ucNBytes;
|
||||
rt_uint8_t *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 = ( rt_uint16_t )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
|
||||
usRegAddress |= ( rt_uint16_t )( 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] );
|
||||
usCoilCount = ( rt_uint16_t )( pucFrame[MB_PDU_FUNC_READ_COILCNT_OFF] << 8 );
|
||||
usCoilCount |= ( rt_uint16_t )( 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.
|
||||
@@ -103,11 +61,11 @@ eMBFuncReadCoils( UCHAR * pucFrame, USHORT * usLen )
|
||||
* byte is only partially field with unused coils set to zero. */
|
||||
if( ( usCoilCount & 0x0007 ) != 0 )
|
||||
{
|
||||
ucNBytes = ( UCHAR )( usCoilCount / 8 + 1 );
|
||||
ucNBytes = ( rt_uint8_t )( usCoilCount / 8 + 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
ucNBytes = ( UCHAR )( usCoilCount / 8 );
|
||||
ucNBytes = ( rt_uint8_t )( usCoilCount / 8 );
|
||||
}
|
||||
*pucFrameCur++ = ucNBytes;
|
||||
*usLen += 1;
|
||||
@@ -142,22 +100,19 @@ eMBFuncReadCoils( UCHAR * pucFrame, USHORT * usLen )
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MB_FUNC_WRITE_COIL_ENABLED > 0
|
||||
eMBException
|
||||
eMBFuncWriteCoil( UCHAR * pucFrame, USHORT * usLen )
|
||||
eMBException eMBFuncWriteCoil( rt_uint8_t * pucFrame, rt_uint16_t * usLen )
|
||||
{
|
||||
USHORT usRegAddress;
|
||||
UCHAR ucBuf[2];
|
||||
rt_uint16_t usRegAddress;
|
||||
rt_uint8_t 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 = ( rt_uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF] << 8 );
|
||||
usRegAddress |= ( rt_uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF + 1] );
|
||||
usRegAddress++;
|
||||
|
||||
if( ( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF + 1] == 0x00 ) &&
|
||||
@@ -196,39 +151,36 @@ eMBFuncWriteCoil( UCHAR * pucFrame, USHORT * usLen )
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED > 0
|
||||
eMBException
|
||||
eMBFuncWriteMultipleCoils( UCHAR * pucFrame, USHORT * usLen )
|
||||
eMBException eMBFuncWriteMultipleCoils( rt_uint8_t * pucFrame, rt_uint16_t * usLen )
|
||||
{
|
||||
USHORT usRegAddress;
|
||||
USHORT usCoilCnt;
|
||||
UCHAR ucByteCount;
|
||||
UCHAR ucByteCountVerify;
|
||||
rt_uint16_t usRegAddress;
|
||||
rt_uint16_t usCoilCnt;
|
||||
rt_uint8_t ucByteCount;
|
||||
rt_uint8_t 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 = ( rt_uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF] << 8 );
|
||||
usRegAddress |= ( rt_uint16_t )( 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] );
|
||||
usCoilCnt = ( rt_uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF] << 8 );
|
||||
usCoilCnt |= ( rt_uint16_t )( 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 );
|
||||
ucByteCountVerify = ( rt_uint8_t )( usCoilCnt / 8 + 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
ucByteCountVerify = ( UCHAR )( usCoilCnt / 8 );
|
||||
ucByteCountVerify = ( rt_uint8_t )( usCoilCnt / 8 );
|
||||
}
|
||||
|
||||
if( ( usCoilCnt >= 1 ) &&
|
||||
@@ -266,4 +218,4 @@ eMBFuncWriteMultipleCoils( UCHAR * pucFrame, USHORT * usLen )
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "mb.h"
|
||||
|
||||
#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 )
|
||||
|
||||
eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
|
||||
|
||||
eMBException eMBFuncReadDiscreteInputs( rt_uint8_t * pucFrame, rt_uint16_t * usLen )
|
||||
{
|
||||
rt_uint16_t usRegAddress;
|
||||
rt_uint16_t usDiscreteCnt;
|
||||
rt_uint8_t ucNBytes;
|
||||
rt_uint8_t *pucFrameCur;
|
||||
|
||||
eMBException eStatus = MB_EX_NONE;
|
||||
eMBErrorCode eRegStatus;
|
||||
|
||||
if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
|
||||
{
|
||||
usRegAddress = ( rt_uint16_t )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
|
||||
usRegAddress |= ( rt_uint16_t )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
|
||||
usRegAddress++;
|
||||
|
||||
usDiscreteCnt = ( rt_uint16_t )( pucFrame[MB_PDU_FUNC_READ_DISCCNT_OFF] << 8 );
|
||||
usDiscreteCnt |= ( rt_uint16_t )( 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 = ( rt_uint8_t ) ( usDiscreteCnt / 8 + 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
ucNBytes = ( rt_uint8_t ) ( 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;
|
||||
}
|
||||
|
||||
|
||||
+45
-96
@@ -1,47 +1,12 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.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"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* ----------------------- Platform includes --------------------------------*/
|
||||
#include "port.h"
|
||||
#include <rtthread.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 )
|
||||
@@ -66,24 +31,18 @@
|
||||
#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 );
|
||||
eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
|
||||
#if MB_FUNC_WRITE_HOLDING_ENABLED > 0
|
||||
|
||||
eMBException
|
||||
eMBFuncWriteHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
|
||||
eMBException eMBFuncWriteHoldingRegister( rt_uint8_t * pucFrame, rt_uint16_t * usLen )
|
||||
{
|
||||
USHORT usRegAddress;
|
||||
rt_uint16_t 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 = ( rt_uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF] << 8 );
|
||||
usRegAddress |= ( rt_uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF + 1] );
|
||||
usRegAddress++;
|
||||
|
||||
/* Make callback to update the value. */
|
||||
@@ -103,33 +62,30 @@ eMBFuncWriteHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED > 0
|
||||
eMBException
|
||||
eMBFuncWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
|
||||
eMBException eMBFuncWriteMultipleHoldingRegister( rt_uint8_t * pucFrame, rt_uint16_t * usLen )
|
||||
{
|
||||
USHORT usRegAddress;
|
||||
USHORT usRegCount;
|
||||
UCHAR ucRegByteCount;
|
||||
rt_uint16_t usRegAddress;
|
||||
rt_uint16_t usRegCount;
|
||||
rt_uint8_t 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 = ( rt_uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF] << 8 );
|
||||
usRegAddress |= ( rt_uint16_t )( 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] );
|
||||
usRegCount = ( rt_uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF] << 8 );
|
||||
usRegCount |= ( rt_uint16_t )( 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 ) ) )
|
||||
( ucRegByteCount == ( rt_uint8_t ) ( 2 * usRegCount ) ) )
|
||||
{
|
||||
/* Make callback to update the register values. */
|
||||
eRegStatus =
|
||||
@@ -162,28 +118,24 @@ eMBFuncWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MB_FUNC_READ_HOLDING_ENABLED > 0
|
||||
|
||||
eMBException
|
||||
eMBFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
|
||||
eMBException eMBFuncReadHoldingRegister( rt_uint8_t * pucFrame, rt_uint16_t * usLen )
|
||||
{
|
||||
USHORT usRegAddress;
|
||||
USHORT usRegCount;
|
||||
UCHAR *pucFrameCur;
|
||||
rt_uint16_t usRegAddress;
|
||||
rt_uint16_t usRegCount;
|
||||
rt_uint8_t *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 = ( rt_uint16_t )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
|
||||
usRegAddress |= ( rt_uint16_t )( 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] );
|
||||
usRegCount = ( rt_uint16_t )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] << 8 );
|
||||
usRegCount |= ( rt_uint16_t )( 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.
|
||||
@@ -199,7 +151,7 @@ eMBFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
|
||||
*usLen += 1;
|
||||
|
||||
/* Second byte in the response contain the number of bytes. */
|
||||
*pucFrameCur++ = ( UCHAR ) ( usRegCount * 2 );
|
||||
*pucFrameCur++ = ( rt_uint8_t ) ( usRegCount * 2 );
|
||||
*usLen += 1;
|
||||
|
||||
/* Make callback to fill the buffer. */
|
||||
@@ -227,38 +179,34 @@ eMBFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if MB_FUNC_READWRITE_HOLDING_ENABLED > 0
|
||||
|
||||
eMBException
|
||||
eMBFuncReadWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
|
||||
eMBException eMBFuncReadWriteMultipleHoldingRegister( rt_uint8_t * pucFrame, rt_uint16_t * usLen )
|
||||
{
|
||||
USHORT usRegReadAddress;
|
||||
USHORT usRegReadCount;
|
||||
USHORT usRegWriteAddress;
|
||||
USHORT usRegWriteCount;
|
||||
UCHAR ucRegWriteByteCount;
|
||||
UCHAR *pucFrameCur;
|
||||
rt_uint16_t usRegReadAddress;
|
||||
rt_uint16_t usRegReadCount;
|
||||
rt_uint16_t usRegWriteAddress;
|
||||
rt_uint16_t usRegWriteCount;
|
||||
rt_uint8_t ucRegWriteByteCount;
|
||||
rt_uint8_t *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 = ( rt_uint16_t )( pucFrame[MB_PDU_FUNC_READWRITE_READ_ADDR_OFF] << 8U );
|
||||
usRegReadAddress |= ( rt_uint16_t )( 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] );
|
||||
usRegReadCount = ( rt_uint16_t )( pucFrame[MB_PDU_FUNC_READWRITE_READ_REGCNT_OFF] << 8U );
|
||||
usRegReadCount |= ( rt_uint16_t )( 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 = ( rt_uint16_t )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_ADDR_OFF] << 8U );
|
||||
usRegWriteAddress |= ( rt_uint16_t )( 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] );
|
||||
usRegWriteCount = ( rt_uint16_t )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_REGCNT_OFF] << 8U );
|
||||
usRegWriteCount |= ( rt_uint16_t )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_REGCNT_OFF + 1] );
|
||||
|
||||
ucRegWriteByteCount = pucFrame[MB_PDU_FUNC_READWRITE_BYTECNT_OFF];
|
||||
|
||||
@@ -281,7 +229,7 @@ eMBFuncReadWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
|
||||
*usLen += 1;
|
||||
|
||||
/* Second byte in the response contain the number of bytes. */
|
||||
*pucFrameCur++ = ( UCHAR ) ( usRegReadCount * 2 );
|
||||
*pucFrameCur++ = ( rt_uint8_t ) ( usRegReadCount * 2 );
|
||||
*usLen += 1;
|
||||
|
||||
/* Make the read callback. */
|
||||
@@ -305,4 +253,5 @@ eMBFuncReadWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "mb.h"
|
||||
|
||||
|
||||
#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 )
|
||||
|
||||
eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
|
||||
|
||||
|
||||
eMBException eMBFuncReadInputRegister( rt_uint8_t * pucFrame, rt_uint16_t * usLen )
|
||||
{
|
||||
rt_uint16_t usRegAddress;
|
||||
rt_uint16_t usRegCount;
|
||||
rt_uint8_t *pucFrameCur;
|
||||
|
||||
eMBException eStatus = MB_EX_NONE;
|
||||
eMBErrorCode eRegStatus;
|
||||
|
||||
if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
|
||||
{
|
||||
usRegAddress = ( rt_uint16_t )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
|
||||
usRegAddress |= ( rt_uint16_t )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
|
||||
usRegAddress++;
|
||||
|
||||
usRegCount = ( rt_uint16_t )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] << 8 );
|
||||
usRegCount |= ( rt_uint16_t )( 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++ = ( rt_uint8_t )( 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "mb.h"
|
||||
|
||||
|
||||
#define MB_FUNC_OTHER_REP_SLAVEID_BUF (32)
|
||||
|
||||
static rt_uint8_t ucMBSlaveID[MB_FUNC_OTHER_REP_SLAVEID_BUF];
|
||||
static rt_uint16_t usMBSlaveIDLen;
|
||||
|
||||
|
||||
eMBErrorCode eMBSetSlaveID( rt_uint8_t ucSlaveID, rt_uint8_t xIsRunning,
|
||||
rt_uint8_t const *pucAdditional, rt_uint16_t 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++] = ( rt_uint8_t )( xIsRunning ? 0xFF : 0x00 );
|
||||
if( usAdditionalLen > 0 )
|
||||
{
|
||||
memcpy( &ucMBSlaveID[usMBSlaveIDLen], pucAdditional,
|
||||
( size_t )usAdditionalLen );
|
||||
usMBSlaveIDLen += usAdditionalLen;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_ENORES;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
eMBException eMBFuncReportSlaveID( rt_uint8_t * pucFrame, rt_uint16_t * usLen )
|
||||
{
|
||||
memcpy( &pucFrame[MB_PDU_DATA_OFF], &ucMBSlaveID[0], ( size_t )usMBSlaveIDLen );
|
||||
*usLen = ( rt_uint16_t )( MB_PDU_DATA_OFF + usMBSlaveIDLen );
|
||||
return MB_EX_NONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
#include "mbport.h"
|
||||
|
||||
static struct rt_semaphore lock;
|
||||
static int is_inited = 0;
|
||||
|
||||
void EnterCriticalSection(void)
|
||||
{
|
||||
rt_err_t err;
|
||||
if (!is_inited) {
|
||||
err = rt_sem_init(&lock, "mb.lock", 1, RT_IPC_FLAG_PRIO);
|
||||
if(err != RT_EOK) {
|
||||
rt_kprintf("modbus critical init failed!\r\n");
|
||||
}
|
||||
is_inited = 1;
|
||||
}
|
||||
rt_sem_take(&lock, RT_WAITING_FOREVER);
|
||||
}
|
||||
|
||||
void ExitCriticalSection(void)
|
||||
{
|
||||
rt_sem_release(&lock);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
#ifndef __MB_PORT_H__
|
||||
#define __MB_PORT_H__
|
||||
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rthw.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "mb.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
rt_uint8_t xMBPortEventInit( void );
|
||||
|
||||
rt_uint8_t xMBPortEventPost( eMBEventType eEvent );
|
||||
|
||||
rt_uint8_t xMBPortEventGet( /*@out@ */ eMBEventType * eEvent );
|
||||
|
||||
rt_uint8_t xMBPortSerialInit( rt_uint8_t ucPort, rt_uint32_t ulBaudRate,
|
||||
rt_uint8_t ucDataBits, eMBParity eParity );
|
||||
|
||||
void vMBPortClose( void );
|
||||
|
||||
void xMBPortSerialClose( void );
|
||||
|
||||
void vMBPortSerialEnable( rt_uint8_t xRxEnable, rt_uint8_t xTxEnable );
|
||||
|
||||
rt_uint8_t xMBPortSerialGetByte(char * pucByte );
|
||||
|
||||
rt_uint8_t xMBPortSerialPutByte(char ucByte );
|
||||
|
||||
rt_uint8_t xMBPortTimersInit( rt_uint16_t usTimeOut50us );
|
||||
|
||||
void xMBPortTimersClose( void );
|
||||
|
||||
void vMBPortTimersEnable( void );
|
||||
|
||||
void vMBPortTimersDisable( void );
|
||||
|
||||
|
||||
/*!
|
||||
* \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 rt_uint8_t( *pxMBFrameCBByteReceived ) ( void );
|
||||
|
||||
extern rt_uint8_t( *pxMBFrameCBTransmitterEmpty ) ( void );
|
||||
|
||||
extern rt_uint8_t( *pxMBPortCBTimerExpired ) ( void );
|
||||
|
||||
void EnterCriticalSection(void);
|
||||
void ExitCriticalSection(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,90 +1,49 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.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
|
||||
{
|
||||
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
|
||||
{
|
||||
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];
|
||||
volatile rt_uint8_t ucRTUBuf[MB_SER_PDU_SIZE_MAX];
|
||||
|
||||
static volatile UCHAR *pucSndBufferCur;
|
||||
static volatile USHORT usSndBufferCount;
|
||||
static volatile rt_uint8_t *pucSndBufferCur;
|
||||
static volatile rt_uint16_t usSndBufferCount;
|
||||
|
||||
static volatile USHORT usRcvBufferPos;
|
||||
static volatile rt_uint16_t usRcvBufferPos;
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
eMBErrorCode
|
||||
eMBRTUInit( UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity )
|
||||
eMBErrorCode eMBRTUInit( rt_uint8_t ucSlaveAddress, rt_uint8_t ucPort,
|
||||
rt_uint32_t ulBaudRate, eMBParity eParity )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
ULONG usTimerT35_50us;
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
rt_uint32_t usTimerT35_50us;
|
||||
|
||||
( void )ucSlaveAddress;
|
||||
ENTER_CRITICAL_SECTION( );
|
||||
EnterCriticalSection();
|
||||
|
||||
/* Modbus RTU uses 8 Databits. */
|
||||
/* If baudrate > 19200 then we should use the fixed timer values
|
||||
@@ -107,7 +66,7 @@ eMBRTUInit( UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity ePar
|
||||
usTimerT35_50us = ( 7UL * 220000UL ) / ( 2UL * ulBaudRate );
|
||||
}
|
||||
|
||||
if( xMBPortTimersInit( ( USHORT ) usTimerT35_50us ) != TRUE )
|
||||
if( xMBPortTimersInit( ( rt_uint16_t ) usTimerT35_50us ) != TRUE )
|
||||
{
|
||||
eStatus = MB_EPORTERR;
|
||||
}
|
||||
@@ -115,15 +74,14 @@ eMBRTUInit( UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity ePar
|
||||
{
|
||||
eStatus = MB_EPORTERR;
|
||||
}
|
||||
EXIT_CRITICAL_SECTION( );
|
||||
ExitCriticalSection();
|
||||
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
void
|
||||
eMBRTUStart( void )
|
||||
void eMBRTUStart( void )
|
||||
{
|
||||
ENTER_CRITICAL_SECTION( );
|
||||
EnterCriticalSection();
|
||||
/* 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
|
||||
@@ -131,31 +89,29 @@ eMBRTUStart( void )
|
||||
*/
|
||||
eRcvState = STATE_RX_INIT;
|
||||
vMBPortSerialEnable( TRUE, FALSE );
|
||||
vMBPortTimersEnable( );
|
||||
vMBPortTimersEnable();
|
||||
|
||||
EXIT_CRITICAL_SECTION( );
|
||||
ExitCriticalSection();
|
||||
}
|
||||
|
||||
void
|
||||
eMBRTUStop( void )
|
||||
void eMBRTUStop( void )
|
||||
{
|
||||
ENTER_CRITICAL_SECTION( );
|
||||
EnterCriticalSection();
|
||||
vMBPortSerialEnable( FALSE, FALSE );
|
||||
vMBPortTimersDisable( );
|
||||
EXIT_CRITICAL_SECTION( );
|
||||
vMBPortTimersDisable();
|
||||
ExitCriticalSection();
|
||||
}
|
||||
|
||||
eMBErrorCode
|
||||
eMBRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength )
|
||||
eMBErrorCode eMBRTUReceive( rt_uint8_t * pucRcvAddress, rt_uint8_t ** pucFrame, rt_uint16_t * pusLength )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
|
||||
ENTER_CRITICAL_SECTION( );
|
||||
EnterCriticalSection();
|
||||
RT_ASSERT( usRcvBufferPos <= MB_SER_PDU_SIZE_MAX );
|
||||
|
||||
/* Length and CRC check */
|
||||
if( ( usRcvBufferPos >= MB_SER_PDU_SIZE_MIN )
|
||||
&& ( usMBCRC16( ( UCHAR * ) ucRTUBuf, usRcvBufferPos ) == 0 ) )
|
||||
&& ( usMBCRC16( ( rt_uint8_t * ) ucRTUBuf, usRcvBufferPos ) == 0 ) )
|
||||
{
|
||||
/* Save the address field. All frames are passed to the upper layed
|
||||
* and the decision if a frame is used is done there.
|
||||
@@ -165,27 +121,27 @@ eMBRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength )
|
||||
/* 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 );
|
||||
*pusLength = ( rt_uint16_t )( 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];
|
||||
*pucFrame = ( rt_uint8_t * ) & ucRTUBuf[MB_SER_PDU_PDU_OFF];
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EIO;
|
||||
}
|
||||
|
||||
EXIT_CRITICAL_SECTION( );
|
||||
ExitCriticalSection();
|
||||
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
eMBErrorCode
|
||||
eMBRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength )
|
||||
eMBErrorCode eMBRTUSend( rt_uint8_t ucSlaveAddress, const rt_uint8_t * pucFrame, rt_uint16_t usLength )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
USHORT usCRC16;
|
||||
rt_uint16_t usCRC16;
|
||||
|
||||
ENTER_CRITICAL_SECTION( );
|
||||
EnterCriticalSection();
|
||||
|
||||
/* 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
|
||||
@@ -194,7 +150,7 @@ eMBRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength )
|
||||
if( eRcvState == STATE_RX_IDLE )
|
||||
{
|
||||
/* First byte before the Modbus-PDU is the slave address. */
|
||||
pucSndBufferCur = ( UCHAR * ) pucFrame - 1;
|
||||
pucSndBufferCur = ( rt_uint8_t * ) pucFrame - 1;
|
||||
usSndBufferCount = 1;
|
||||
|
||||
/* Now copy the Modbus-PDU into the Modbus-Serial-Line-PDU. */
|
||||
@@ -202,9 +158,9 @@ eMBRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength )
|
||||
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 );
|
||||
usCRC16 = usMBCRC16( ( rt_uint8_t * ) pucSndBufferCur, usSndBufferCount );
|
||||
ucRTUBuf[usSndBufferCount++] = ( rt_uint8_t )( usCRC16 & 0xFF );
|
||||
ucRTUBuf[usSndBufferCount++] = ( rt_uint8_t )( usCRC16 >> 8 );
|
||||
|
||||
/* Activate the transmitter. */
|
||||
eSndState = STATE_TX_XMIT;
|
||||
@@ -214,20 +170,21 @@ eMBRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength )
|
||||
{
|
||||
eStatus = MB_EIO;
|
||||
}
|
||||
EXIT_CRITICAL_SECTION( );
|
||||
|
||||
ExitCriticalSection();
|
||||
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBRTUReceiveFSM( void )
|
||||
rt_uint8_t xMBRTUReceiveFSM( void )
|
||||
{
|
||||
BOOL xTaskNeedSwitch = FALSE;
|
||||
UCHAR ucByte;
|
||||
rt_uint8_t xTaskNeedSwitch = FALSE;
|
||||
rt_uint8_t ucByte;
|
||||
|
||||
RT_ASSERT( eSndState == STATE_TX_IDLE );
|
||||
|
||||
/* Always read the character. */
|
||||
( void )xMBPortSerialGetByte( ( CHAR * ) & ucByte );
|
||||
( void )xMBPortSerialGetByte((char *) &ucByte);
|
||||
|
||||
switch ( eRcvState )
|
||||
{
|
||||
@@ -235,14 +192,14 @@ xMBRTUReceiveFSM( void )
|
||||
* wait until the frame is finished.
|
||||
*/
|
||||
case STATE_RX_INIT:
|
||||
vMBPortTimersEnable( );
|
||||
vMBPortTimersEnable();
|
||||
break;
|
||||
|
||||
/* In the error state we wait until all characters in the
|
||||
* damaged frame are transmitted.
|
||||
*/
|
||||
case STATE_RX_ERROR:
|
||||
vMBPortTimersEnable( );
|
||||
vMBPortTimersEnable();
|
||||
break;
|
||||
|
||||
/* In the idle state we wait for a new character. If a character
|
||||
@@ -255,7 +212,7 @@ xMBRTUReceiveFSM( void )
|
||||
eRcvState = STATE_RX_RCV;
|
||||
|
||||
/* Enable t3.5 timers. */
|
||||
vMBPortTimersEnable( );
|
||||
vMBPortTimersEnable();
|
||||
break;
|
||||
|
||||
/* We are currently receiving a frame. Reset the timer after
|
||||
@@ -278,10 +235,9 @@ xMBRTUReceiveFSM( void )
|
||||
return xTaskNeedSwitch;
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBRTUTransmitFSM( void )
|
||||
rt_uint8_t xMBRTUTransmitFSM( void )
|
||||
{
|
||||
BOOL xNeedPoll = FALSE;
|
||||
rt_uint8_t xNeedPoll = FALSE;
|
||||
|
||||
RT_ASSERT( eRcvState == STATE_RX_IDLE );
|
||||
|
||||
@@ -298,7 +254,7 @@ xMBRTUTransmitFSM( void )
|
||||
/* check if we are finished. */
|
||||
if( usSndBufferCount != 0 )
|
||||
{
|
||||
xMBPortSerialPutByte( ( CHAR )*pucSndBufferCur );
|
||||
xMBPortSerialPutByte((char)*pucSndBufferCur );
|
||||
pucSndBufferCur++; /* next byte in sendbuffer. */
|
||||
usSndBufferCount--;
|
||||
}
|
||||
@@ -316,10 +272,9 @@ xMBRTUTransmitFSM( void )
|
||||
return xNeedPoll;
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBRTUTimerT35Expired( void )
|
||||
rt_uint8_t xMBRTUTimerT35Expired( void )
|
||||
{
|
||||
BOOL xNeedPoll = FALSE;
|
||||
rt_uint8_t xNeedPoll = FALSE;
|
||||
|
||||
switch ( eRcvState )
|
||||
{
|
||||
@@ -345,8 +300,11 @@ xMBRTUTimerT35Expired( void )
|
||||
break;
|
||||
}
|
||||
|
||||
vMBPortTimersDisable( );
|
||||
vMBPortTimersDisable();
|
||||
eRcvState = STATE_RX_IDLE;
|
||||
|
||||
return xNeedPoll;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef __MB_RTU_H__
|
||||
#define __MB_RTU_H__
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "mb.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
eMBErrorCode eMBRTUInit( rt_uint8_t slaveAddress, rt_uint8_t ucPort,
|
||||
rt_uint32_t ulBaudRate, eMBParity eParity );
|
||||
void eMBRTUStart( void );
|
||||
void eMBRTUStop( void );
|
||||
eMBErrorCode eMBRTUReceive( rt_uint8_t * pucRcvAddress, rt_uint8_t ** pucFrame, rt_uint16_t * pusLength );
|
||||
eMBErrorCode eMBRTUSend( rt_uint8_t slaveAddress, const rt_uint8_t * pucFrame, rt_uint16_t usLength );
|
||||
rt_uint8_t xMBRTUReceiveFSM( void );
|
||||
rt_uint8_t xMBRTUTransmitFSM( void );
|
||||
rt_uint8_t xMBRTUTimerT15Expired( void );
|
||||
rt_uint8_t xMBRTUTimerT35Expired( void );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,60 +1,35 @@
|
||||
/*
|
||||
* FreeModbus Libary: RT-Thread Port
|
||||
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
|
||||
*
|
||||
* 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.60 2013/08/13 15:07:05 Armink $
|
||||
*/
|
||||
|
||||
#include "port.h"
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mbport.h"
|
||||
#include "rtdevice.h"
|
||||
#include "board.h"
|
||||
|
||||
/* ----------------------- Static variables ---------------------------------*/
|
||||
|
||||
/* software simulation serial transmit IRQ handler thread stack */
|
||||
#ifdef rt_align
|
||||
rt_align(RT_ALIGN_SIZE)
|
||||
#else
|
||||
ALIGN(RT_ALIGN_SIZE)
|
||||
#endif
|
||||
//rt_align(RT_ALIGN_SIZE)
|
||||
|
||||
static rt_uint8_t serial_soft_trans_irq_stack[512];
|
||||
|
||||
/* software simulation serial transmit IRQ handler thread */
|
||||
static struct rt_thread thread_serial_soft_trans_irq;
|
||||
|
||||
/* serial event */
|
||||
static struct rt_event event_serial;
|
||||
|
||||
/* modbus slave serial device */
|
||||
static struct rt_serial_device *serial;
|
||||
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
/* serial transmit event */
|
||||
#define EVENT_SERIAL_TRANS_START (1<<0)
|
||||
|
||||
/* ----------------------- static functions ---------------------------------*/
|
||||
static void prvvUARTTxReadyISR(void);
|
||||
static void prvvUARTRxISR(void);
|
||||
static rt_err_t serial_rx_ind(rt_device_t dev, rt_size_t size);
|
||||
static void serial_soft_trans_irq(void* parameter);
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
|
||||
eMBParity eParity)
|
||||
rt_uint8_t xMBPortSerialInit(rt_uint8_t ucPORT, rt_uint32_t ulBaudRate,
|
||||
rt_uint8_t ucDataBits, eMBParity eParity)
|
||||
{
|
||||
rt_device_t dev = RT_NULL;
|
||||
char uart_name[20];
|
||||
@@ -123,7 +98,7 @@ BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void vMBPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable)
|
||||
void vMBPortSerialEnable(rt_uint8_t xRxEnable, rt_uint8_t xTxEnable)
|
||||
{
|
||||
rt_uint32_t recved_event;
|
||||
if (xRxEnable)
|
||||
@@ -163,13 +138,13 @@ void vMBPortClose(void)
|
||||
serial->parent.close(&(serial->parent));
|
||||
}
|
||||
|
||||
BOOL xMBPortSerialPutByte(CHAR ucByte)
|
||||
rt_uint8_t xMBPortSerialPutByte(char ucByte)
|
||||
{
|
||||
serial->parent.write(&(serial->parent), 0, &ucByte, 1);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL xMBPortSerialGetByte(CHAR * pucByte)
|
||||
rt_uint8_t xMBPortSerialGetByte(char * pucByte)
|
||||
{
|
||||
serial->parent.read(&(serial->parent), 0, pucByte, 1);
|
||||
return TRUE;
|
||||
@@ -228,3 +203,6 @@ static rt_err_t serial_rx_ind(rt_device_t dev, rt_size_t size) {
|
||||
prvvUARTRxISR();
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "mb.h"
|
||||
#include "mbport.h"
|
||||
|
||||
static struct rt_timer timer;
|
||||
|
||||
void vMBPortTimersEnable()
|
||||
{
|
||||
rt_timer_start(&timer);
|
||||
}
|
||||
|
||||
void vMBPortTimersDisable()
|
||||
{
|
||||
rt_timer_stop(&timer);
|
||||
}
|
||||
|
||||
static void prvvTIMERExpiredISR(void)
|
||||
{
|
||||
(void)pxMBPortCBTimerExpired();
|
||||
}
|
||||
|
||||
static void timer_timeout_ind(void* parameter)
|
||||
{
|
||||
prvvTIMERExpiredISR();
|
||||
}
|
||||
|
||||
rt_uint8_t xMBPortTimersInit(rt_uint16_t usTim1Timerout50us)
|
||||
{
|
||||
rt_timer_init(&timer, "tmr.mb",
|
||||
timer_timeout_ind, /* bind timeout callback function */
|
||||
RT_NULL,
|
||||
(50 * usTim1Timerout50us) / (1000 * 1000 / RT_TICK_PER_SECOND) + 1,
|
||||
RT_TIMER_FLAG_ONE_SHOT); /* one shot */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mbport.h"
|
||||
|
||||
#include "mb.h"
|
||||
|
||||
#define BITS_UCHAR 8U
|
||||
|
||||
void xMBUtilSetBits( rt_uint8_t * ucByteBuf, rt_uint16_t usBitOffset,
|
||||
rt_uint8_t ucNBits, rt_uint8_t ucValue )
|
||||
{
|
||||
rt_uint16_t usWordBuf;
|
||||
rt_uint16_t usMask;
|
||||
rt_uint16_t usByteOffset;
|
||||
rt_uint16_t usNPreBits;
|
||||
rt_uint16_t usValue = ucValue;
|
||||
|
||||
RT_ASSERT( ucNBits <= 8 );
|
||||
RT_ASSERT( ( size_t )BITS_UCHAR == sizeof( rt_uint8_t ) * 8 );
|
||||
|
||||
/* Calculate byte offset for first byte containing the bit values starting
|
||||
* at usBitOffset. */
|
||||
usByteOffset = ( rt_uint16_t )( ( usBitOffset ) / BITS_UCHAR );
|
||||
|
||||
/* How many bits precede our bits to set. */
|
||||
usNPreBits = ( rt_uint16_t )( usBitOffset - usByteOffset * BITS_UCHAR );
|
||||
|
||||
/* Move bit field into position over bits to set */
|
||||
usValue <<= usNPreBits;
|
||||
|
||||
/* Prepare a mask for setting the new bits. */
|
||||
usMask = ( rt_uint16_t )( ( 1 << ( rt_uint16_t ) 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 = ( rt_uint16_t )( ( usWordBuf & ( ~usMask ) ) | usValue );
|
||||
|
||||
/* move bits back into storage */
|
||||
ucByteBuf[usByteOffset] = ( rt_uint8_t )( usWordBuf & 0xFF );
|
||||
ucByteBuf[usByteOffset + 1] = ( rt_uint8_t )( usWordBuf >> BITS_UCHAR );
|
||||
}
|
||||
|
||||
rt_uint8_t xMBUtilGetBits( rt_uint8_t * ucByteBuf, rt_uint16_t usBitOffset, rt_uint8_t ucNBits )
|
||||
{
|
||||
rt_uint16_t usWordBuf;
|
||||
rt_uint16_t usMask;
|
||||
rt_uint16_t usByteOffset;
|
||||
rt_uint16_t usNPreBits;
|
||||
|
||||
/* Calculate byte offset for first byte containing the bit values starting
|
||||
* at usBitOffset. */
|
||||
usByteOffset = ( rt_uint16_t )( ( usBitOffset ) / BITS_UCHAR );
|
||||
|
||||
/* How many bits precede our bits to set. */
|
||||
usNPreBits = ( rt_uint16_t )( usBitOffset - usByteOffset * BITS_UCHAR );
|
||||
|
||||
/* Prepare a mask for setting the new bits. */
|
||||
usMask = ( rt_uint16_t )( ( 1 << ( rt_uint16_t ) 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 ( rt_uint8_t ) 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,35 +1,6 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.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
|
||||
#ifndef __MB_UTILS_H__
|
||||
#define __MB_UTILS_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -75,8 +46,8 @@ extern "C" {
|
||||
* xMBUtilSetBits( ucBits, 8, 8, 0x5A);
|
||||
* \endcode
|
||||
*/
|
||||
void xMBUtilSetBits( UCHAR * ucByteBuf, USHORT usBitOffset,
|
||||
UCHAR ucNBits, UCHAR ucValues );
|
||||
void xMBUtilSetBits( rt_uint8_t * ucByteBuf, rt_uint16_t usBitOffset,
|
||||
rt_uint8_t ucNBits, rt_uint8_t ucValues );
|
||||
|
||||
/*! \brief Function to read bits in a byte buffer.
|
||||
*
|
||||
@@ -90,21 +61,21 @@ void xMBUtilSetBits( UCHAR * ucByteBuf, USHORT usBitOffset,
|
||||
* than 8.
|
||||
*
|
||||
* \code
|
||||
* UCHAR ucBits[2] = {0, 0};
|
||||
* UCHAR ucResult;
|
||||
* rt_uint8_t ucBits[2] = {0, 0};
|
||||
* rt_uint8_t ucResult;
|
||||
*
|
||||
* // Extract the bits 3 - 10.
|
||||
* ucResult = xMBUtilGetBits( ucBits, 3, 8 );
|
||||
* \endcode
|
||||
*/
|
||||
UCHAR xMBUtilGetBits( UCHAR * ucByteBuf, USHORT usBitOffset,
|
||||
UCHAR ucNBits );
|
||||
rt_uint8_t xMBUtilGetBits( rt_uint8_t * ucByteBuf, rt_uint16_t usBitOffset, rt_uint8_t ucNBits );
|
||||
|
||||
/*! @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "mb.h"
|
||||
#include "chrg_mb.h"
|
||||
#include "chrg_comm.h"
|
||||
|
||||
|
||||
#define LOG_TAG "chrg.comm"
|
||||
#define DBG_LEVEL DBG_LOG
|
||||
#include <rtdbg.h>
|
||||
|
||||
extern rt_uint16_t usSRegHoldBuf[RT_S_REG_HOLDING_NREGS];
|
||||
extern rt_uint16_t usSRegHoldBuf[S_REG_HOLDING_NREGS];
|
||||
|
||||
struct chrg_comm_t chrgcomm = {
|
||||
.tid_poll = RT_NULL,
|
||||
@@ -49,7 +51,7 @@ static void chrg_comm_poll (void *pdata)
|
||||
return ;
|
||||
}
|
||||
|
||||
eMBInit(MB_RTU, pCOMM->addr, 1, 115200, MB_PAR_EVEN);
|
||||
eMBInit(pCOMM->addr, 1, 115200, MB_PAR_EVEN);
|
||||
|
||||
eMBEnable();
|
||||
|
||||
|
||||
@@ -1,46 +1,26 @@
|
||||
/*
|
||||
* FreeModbus Libary: user callback functions and buffer define in slave mode
|
||||
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
|
||||
*
|
||||
* 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: user_mb_app.c,v 1.60 2013/11/23 11:49:05 Armink $
|
||||
*/
|
||||
#include "user_mb_app.h"
|
||||
|
||||
/*------------------------Slave mode use these variables----------------------*/
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "mb.h"
|
||||
#include "mbutils.h"
|
||||
|
||||
#include "chrg_mb.h"
|
||||
|
||||
//Slave mode:DiscreteInputs variables
|
||||
USHORT usSDiscInStart = S_DISCRETE_INPUT_START;
|
||||
#if S_DISCRETE_INPUT_NDISCRETES%8
|
||||
UCHAR ucSDiscInBuf[S_DISCRETE_INPUT_NDISCRETES/8+1];
|
||||
#else
|
||||
UCHAR ucSDiscInBuf[S_DISCRETE_INPUT_NDISCRETES/8] ;
|
||||
#endif
|
||||
rt_uint16_t usSDiscInStart = S_DISCRETE_INPUT_START;
|
||||
rt_uint8_t ucSDiscInBuf[(S_DISCRETE_INPUT_NDISCRETES+7)/8];
|
||||
|
||||
//Slave mode:Coils variables
|
||||
USHORT usSCoilStart = S_COIL_START;
|
||||
#if S_COIL_NCOILS%8
|
||||
UCHAR ucSCoilBuf[S_COIL_NCOILS/8+1] ;
|
||||
#else
|
||||
UCHAR ucSCoilBuf[S_COIL_NCOILS/8] ;
|
||||
#endif
|
||||
rt_uint16_t usSCoilStart = S_COIL_START;
|
||||
rt_uint8_t ucSCoilBuf[(S_COIL_NCOILS+7)/8];
|
||||
|
||||
//Slave mode:InputRegister variables
|
||||
USHORT usSRegInStart = S_REG_INPUT_START;
|
||||
USHORT usSRegInBuf[S_REG_INPUT_NREGS] ;
|
||||
rt_uint16_t usSRegInStart = S_REG_INPUT_START;
|
||||
rt_uint16_t usSRegInBuf[S_REG_INPUT_NREGS];
|
||||
|
||||
//Slave mode:HoldingRegister variables
|
||||
USHORT usSRegHoldStart = S_REG_HOLDING_START;
|
||||
USHORT usSRegHoldBuf[S_REG_HOLDING_NREGS] ;
|
||||
rt_uint16_t usSRegHoldStart = S_REG_HOLDING_START;
|
||||
rt_uint16_t usSRegHoldBuf[S_REG_HOLDING_NREGS];
|
||||
|
||||
/**
|
||||
* Modbus slave input register callback function.
|
||||
@@ -51,14 +31,14 @@ USHORT usSRegHoldBuf[S_REG_HOLDING_NREGS] ;
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
eMBErrorCode eMBRegInputCB(UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
|
||||
eMBErrorCode eMBRegInputCB(rt_uint8_t * pucRegBuffer, rt_uint16_t usAddress, rt_uint16_t usNRegs )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
USHORT iRegIndex;
|
||||
USHORT * pusRegInputBuf;
|
||||
USHORT REG_INPUT_START;
|
||||
USHORT REG_INPUT_NREGS;
|
||||
USHORT usRegInStart;
|
||||
rt_uint16_t iRegIndex;
|
||||
rt_uint16_t * pusRegInputBuf;
|
||||
rt_uint16_t REG_INPUT_START;
|
||||
rt_uint16_t REG_INPUT_NREGS;
|
||||
rt_uint16_t usRegInStart;
|
||||
|
||||
pusRegInputBuf = usSRegInBuf;
|
||||
REG_INPUT_START = S_REG_INPUT_START;
|
||||
@@ -74,8 +54,8 @@ eMBErrorCode eMBRegInputCB(UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNReg
|
||||
iRegIndex = usAddress - usRegInStart;
|
||||
while (usNRegs > 0)
|
||||
{
|
||||
*pucRegBuffer++ = (UCHAR) (pusRegInputBuf[iRegIndex] >> 8);
|
||||
*pucRegBuffer++ = (UCHAR) (pusRegInputBuf[iRegIndex] & 0xFF);
|
||||
*pucRegBuffer++ = (rt_uint8_t) (pusRegInputBuf[iRegIndex] >> 8);
|
||||
*pucRegBuffer++ = (rt_uint8_t) (pusRegInputBuf[iRegIndex] & 0xFF);
|
||||
iRegIndex++;
|
||||
usNRegs--;
|
||||
}
|
||||
@@ -98,15 +78,15 @@ eMBErrorCode eMBRegInputCB(UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNReg
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
eMBErrorCode eMBRegHoldingCB(UCHAR * pucRegBuffer, USHORT usAddress,
|
||||
USHORT usNRegs, eMBRegisterMode eMode)
|
||||
eMBErrorCode eMBRegHoldingCB(rt_uint8_t * pucRegBuffer, rt_uint16_t usAddress,
|
||||
rt_uint16_t usNRegs, eMBRegisterMode eMode)
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
USHORT iRegIndex;
|
||||
USHORT * pusRegHoldingBuf;
|
||||
USHORT REG_HOLDING_START;
|
||||
USHORT REG_HOLDING_NREGS;
|
||||
USHORT usRegHoldStart;
|
||||
rt_uint16_t iRegIndex;
|
||||
rt_uint16_t * pusRegHoldingBuf;
|
||||
rt_uint16_t REG_HOLDING_START;
|
||||
rt_uint16_t REG_HOLDING_NREGS;
|
||||
rt_uint16_t usRegHoldStart;
|
||||
|
||||
pusRegHoldingBuf = usSRegHoldBuf;
|
||||
REG_HOLDING_START = S_REG_HOLDING_START;
|
||||
@@ -126,8 +106,8 @@ eMBErrorCode eMBRegHoldingCB(UCHAR * pucRegBuffer, USHORT usAddress,
|
||||
case MB_REG_READ:
|
||||
while (usNRegs > 0)
|
||||
{
|
||||
*pucRegBuffer++ = (UCHAR) (pusRegHoldingBuf[iRegIndex] >> 8);
|
||||
*pucRegBuffer++ = (UCHAR) (pusRegHoldingBuf[iRegIndex] & 0xFF);
|
||||
*pucRegBuffer++ = (rt_uint8_t) (pusRegHoldingBuf[iRegIndex] >> 8);
|
||||
*pucRegBuffer++ = (rt_uint8_t) (pusRegHoldingBuf[iRegIndex] & 0xFF);
|
||||
iRegIndex++;
|
||||
usNRegs--;
|
||||
}
|
||||
@@ -162,15 +142,15 @@ eMBErrorCode eMBRegHoldingCB(UCHAR * pucRegBuffer, USHORT usAddress,
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
eMBErrorCode eMBRegCoilsCB(UCHAR * pucRegBuffer, USHORT usAddress,
|
||||
USHORT usNCoils, eMBRegisterMode eMode)
|
||||
eMBErrorCode eMBRegCoilsCB(rt_uint8_t * pucRegBuffer, rt_uint16_t usAddress,
|
||||
rt_uint16_t usNCoils, eMBRegisterMode eMode)
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
USHORT iRegIndex , iRegBitIndex , iNReg;
|
||||
UCHAR * pucCoilBuf;
|
||||
USHORT COIL_START;
|
||||
USHORT COIL_NCOILS;
|
||||
USHORT usCoilStart;
|
||||
rt_uint16_t iRegIndex , iRegBitIndex , iNReg;
|
||||
rt_uint8_t * pucCoilBuf;
|
||||
rt_uint16_t COIL_START;
|
||||
rt_uint16_t COIL_NCOILS;
|
||||
rt_uint16_t usCoilStart;
|
||||
iNReg = usNCoils / 8 + 1;
|
||||
|
||||
pucCoilBuf = ucSCoilBuf;
|
||||
@@ -184,8 +164,8 @@ eMBErrorCode eMBRegCoilsCB(UCHAR * pucRegBuffer, USHORT usAddress,
|
||||
if( ( usAddress >= COIL_START ) &&
|
||||
( usAddress + usNCoils <= COIL_START + COIL_NCOILS ) )
|
||||
{
|
||||
iRegIndex = (USHORT) (usAddress - usCoilStart) / 8;
|
||||
iRegBitIndex = (USHORT) (usAddress - usCoilStart) % 8;
|
||||
iRegIndex = (rt_uint16_t) (usAddress - usCoilStart) / 8;
|
||||
iRegBitIndex = (rt_uint16_t) (usAddress - usCoilStart) % 8;
|
||||
switch ( eMode )
|
||||
{
|
||||
/* read current coil values from the protocol stack. */
|
||||
@@ -239,14 +219,14 @@ eMBErrorCode eMBRegCoilsCB(UCHAR * pucRegBuffer, USHORT usAddress,
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
|
||||
eMBErrorCode eMBRegDiscreteCB( rt_uint8_t * pucRegBuffer, rt_uint16_t usAddress, rt_uint16_t usNDiscrete )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
USHORT iRegIndex , iRegBitIndex , iNReg;
|
||||
UCHAR * pucDiscreteInputBuf;
|
||||
USHORT DISCRETE_INPUT_START;
|
||||
USHORT DISCRETE_INPUT_NDISCRETES;
|
||||
USHORT usDiscreteInputStart;
|
||||
rt_uint16_t iRegIndex , iRegBitIndex , iNReg;
|
||||
rt_uint8_t * pucDiscreteInputBuf;
|
||||
rt_uint16_t DISCRETE_INPUT_START;
|
||||
rt_uint16_t DISCRETE_INPUT_NDISCRETES;
|
||||
rt_uint16_t usDiscreteInputStart;
|
||||
iNReg = usNDiscrete / 8 + 1;
|
||||
|
||||
pucDiscreteInputBuf = ucSDiscInBuf;
|
||||
@@ -260,8 +240,8 @@ eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT us
|
||||
if ((usAddress >= DISCRETE_INPUT_START)
|
||||
&& (usAddress + usNDiscrete <= DISCRETE_INPUT_START + DISCRETE_INPUT_NDISCRETES))
|
||||
{
|
||||
iRegIndex = (USHORT) (usAddress - usDiscreteInputStart) / 8;
|
||||
iRegBitIndex = (USHORT) (usAddress - usDiscreteInputStart) % 8;
|
||||
iRegIndex = (rt_uint16_t) (usAddress - usDiscreteInputStart) / 8;
|
||||
iRegBitIndex = (rt_uint16_t) (usAddress - usDiscreteInputStart) % 8;
|
||||
|
||||
while (iNReg > 0)
|
||||
{
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef __CHRG_MB_H__
|
||||
#define __CHRG_MB_H__
|
||||
|
||||
|
||||
#define S_DISCRETE_INPUT_START 0
|
||||
#define S_DISCRETE_INPUT_NDISCRETES 16
|
||||
#define S_COIL_START 0
|
||||
#define S_COIL_NCOILS 64
|
||||
#define S_REG_INPUT_START 0
|
||||
#define S_REG_INPUT_NREGS 100
|
||||
#define S_REG_HOLDING_START 0
|
||||
#define S_REG_HOLDING_NREGS 100
|
||||
|
||||
/* salve mode: holding register's all address */
|
||||
#define S_HD_RESERVE 0
|
||||
/* salve mode: input register's all address */
|
||||
#define S_IN_RESERVE 0
|
||||
/* salve mode: coil's all address */
|
||||
#define S_CO_RESERVE 0
|
||||
/* salve mode: discrete's all address */
|
||||
#define S_DI_RESERVE 0
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -209,26 +209,6 @@
|
||||
|
||||
/* IoT - internet of things */
|
||||
|
||||
#define PKG_USING_FREEMODBUS
|
||||
#define PKG_MODBUS_SLAVE
|
||||
|
||||
/* advanced configuration */
|
||||
|
||||
#define RT_S_DISCRETE_INPUT_START 0
|
||||
#define RT_S_DISCRETE_INPUT_NDISCRETES 16
|
||||
#define RT_S_COIL_START 0
|
||||
#define RT_S_COIL_NCOILS 64
|
||||
#define RT_S_REG_INPUT_START 0
|
||||
#define RT_S_REG_INPUT_NREGS 100
|
||||
#define RT_S_REG_HOLDING_START 0
|
||||
#define RT_S_REG_HOLDING_NREGS 100
|
||||
#define RT_S_HD_RESERVE 0
|
||||
#define RT_S_IN_RESERVE 0
|
||||
#define RT_S_CO_RESERVE 0
|
||||
#define RT_S_DI_RESERVE 0
|
||||
/* end of advanced configuration */
|
||||
#define PKG_MODBUS_SLAVE_RTU
|
||||
#define PKG_USING_FREEMODBUS_LATEST_VERSION
|
||||
|
||||
/* Wi-Fi */
|
||||
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
Import('RTT_ROOT')
|
||||
from building import *
|
||||
|
||||
src = Split("""
|
||||
modbus/functions/mbfuncdiag.c
|
||||
modbus/functions/mbutils.c
|
||||
modbus/functions/mbfuncother.c
|
||||
modbus/rtu/mbcrc.c
|
||||
port/port.c
|
||||
""")
|
||||
|
||||
master_rtu_src = Split("""
|
||||
modbus/functions/mbfunccoils_m.c
|
||||
modbus/functions/mbfuncdisc_m.c
|
||||
modbus/functions/mbfuncholding_m.c
|
||||
modbus/functions/mbfuncinput_m.c
|
||||
modbus/rtu/mbrtu_m.c
|
||||
modbus/mb_m.c
|
||||
port/portevent_m.c
|
||||
port/portserial_m.c
|
||||
port/porttimer_m.c
|
||||
port/user_mb_app_m.c
|
||||
""")
|
||||
|
||||
slave_src = Split("""
|
||||
modbus/functions/mbfunccoils.c
|
||||
modbus/functions/mbfuncdisc.c
|
||||
modbus/functions/mbfuncholding.c
|
||||
modbus/functions/mbfuncinput.c
|
||||
modbus/mb.c
|
||||
port/portevent.c
|
||||
port/portserial.c
|
||||
port/porttcp.c
|
||||
port/porttimer.c
|
||||
port/user_mb_app.c
|
||||
""")
|
||||
|
||||
# The set of source files associated with this SConscript file.
|
||||
path = [GetCurrentDir() + '/modbus/include',
|
||||
GetCurrentDir() + '/modbus/rtu',
|
||||
GetCurrentDir() + '/modbus/ascii',
|
||||
GetCurrentDir() + '/modbus/tcp',
|
||||
GetCurrentDir() + '/port']
|
||||
|
||||
if GetDepend(['PKG_MODBUS_MASTER_RTU']):
|
||||
src += master_rtu_src
|
||||
|
||||
if GetDepend(['PKG_MODBUS_SLAVE']):
|
||||
src += slave_src
|
||||
|
||||
if GetDepend(['PKG_MODBUS_SLAVE_RTU']):
|
||||
src += ['modbus/rtu/mbrtu.c']
|
||||
|
||||
if GetDepend(['PKG_MODBUS_SLAVE_ASCII']):
|
||||
src += ['modbus/ascii/mbascii.c']
|
||||
src += ['modbus/rtu/mbrtu.c']
|
||||
|
||||
if GetDepend(['PKG_MODBUS_SLAVE_TCP']):
|
||||
src += ['modbus/tcp/mbtcp.c']
|
||||
|
||||
if GetDepend(['PKG_MODBUS_MASTER_SAMPLE']):
|
||||
src += ['samples/sample_mb_master.c']
|
||||
|
||||
if GetDepend(['PKG_MODBUS_SLAVE_SAMPLE']):
|
||||
src += ['samples/sample_mb_slave.c']
|
||||
|
||||
group = DefineGroup('FreeModbus', src, depend = ['PKG_USING_FREEMODBUS'], CPPPATH = path)
|
||||
|
||||
Return('group')
|
||||
@@ -1,486 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.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: mbascii.c,v 1.15 2007/02/18 23:46:48 wolti Exp $
|
||||
*/
|
||||
|
||||
/* ----------------------- System includes ----------------------------------*/
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
|
||||
/* ----------------------- Platform includes --------------------------------*/
|
||||
#include "port.h"
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mbconfig.h"
|
||||
#include "mbascii.h"
|
||||
#include "mbframe.h"
|
||||
|
||||
#include "mbcrc.h"
|
||||
#include "mbport.h"
|
||||
|
||||
#if MB_SLAVE_ASCII_ENABLED > 0
|
||||
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
#define MB_ASCII_DEFAULT_CR '\r' /*!< Default CR character for Modbus ASCII. */
|
||||
#define MB_ASCII_DEFAULT_LF '\n' /*!< Default LF character for Modbus ASCII. */
|
||||
#define MB_SER_PDU_SIZE_MIN 3 /*!< Minimum size of a Modbus ASCII frame. */
|
||||
#define MB_SER_PDU_SIZE_MAX 256 /*!< Maximum size of a Modbus ASCII frame. */
|
||||
#define MB_SER_PDU_SIZE_LRC 1 /*!< Size of LRC 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_IDLE, /*!< Receiver is in idle state. */
|
||||
STATE_RX_RCV, /*!< Frame is beeing received. */
|
||||
STATE_RX_WAIT_EOF /*!< Wait for End of Frame. */
|
||||
} eMBRcvState;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
STATE_TX_IDLE, /*!< Transmitter is in idle state. */
|
||||
STATE_TX_START, /*!< Starting transmission (':' sent). */
|
||||
STATE_TX_DATA, /*!< Sending of data (Address, Data, LRC). */
|
||||
STATE_TX_END, /*!< End of transmission. */
|
||||
STATE_TX_NOTIFY /*!< Notify sender that the frame has been sent. */
|
||||
} eMBSndState;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BYTE_HIGH_NIBBLE, /*!< Character for high nibble of byte. */
|
||||
BYTE_LOW_NIBBLE /*!< Character for low nibble of byte. */
|
||||
} eMBBytePos;
|
||||
|
||||
/* ----------------------- Static functions ---------------------------------*/
|
||||
static UCHAR prvucMBCHAR2BIN( UCHAR ucCharacter );
|
||||
|
||||
static UCHAR prvucMBBIN2CHAR( UCHAR ucByte );
|
||||
|
||||
static UCHAR prvucMBLRC( UCHAR * pucFrame, USHORT usLen );
|
||||
|
||||
/* ----------------------- Static variables ---------------------------------*/
|
||||
static volatile eMBSndState eSndState;
|
||||
static volatile eMBRcvState eRcvState;
|
||||
|
||||
/* We reuse the Modbus RTU buffer because only one buffer is needed and the
|
||||
* RTU buffer is bigger. */
|
||||
extern volatile UCHAR ucRTUBuf[];
|
||||
static volatile UCHAR *ucASCIIBuf = ucRTUBuf;
|
||||
|
||||
static volatile USHORT usRcvBufferPos;
|
||||
static volatile eMBBytePos eBytePos;
|
||||
|
||||
static volatile UCHAR *pucSndBufferCur;
|
||||
static volatile USHORT usSndBufferCount;
|
||||
|
||||
static volatile UCHAR ucLRC;
|
||||
static volatile UCHAR ucMBLFCharacter;
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
eMBErrorCode
|
||||
eMBASCIIInit( UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
( void )ucSlaveAddress;
|
||||
|
||||
ENTER_CRITICAL_SECTION( );
|
||||
ucMBLFCharacter = MB_ASCII_DEFAULT_LF;
|
||||
|
||||
if( xMBPortSerialInit( ucPort, ulBaudRate, 7, eParity ) != TRUE )
|
||||
{
|
||||
eStatus = MB_EPORTERR;
|
||||
}
|
||||
else if( xMBPortTimersInit( MB_ASCII_TIMEOUT_SEC * 20000UL ) != TRUE )
|
||||
{
|
||||
eStatus = MB_EPORTERR;
|
||||
}
|
||||
|
||||
EXIT_CRITICAL_SECTION( );
|
||||
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
void
|
||||
eMBASCIIStart( void )
|
||||
{
|
||||
ENTER_CRITICAL_SECTION( );
|
||||
vMBPortSerialEnable( TRUE, FALSE );
|
||||
eRcvState = STATE_RX_IDLE;
|
||||
EXIT_CRITICAL_SECTION( );
|
||||
|
||||
/* No special startup required for ASCII. */
|
||||
( void )xMBPortEventPost( EV_READY );
|
||||
}
|
||||
|
||||
void
|
||||
eMBASCIIStop( void )
|
||||
{
|
||||
ENTER_CRITICAL_SECTION( );
|
||||
vMBPortSerialEnable( FALSE, FALSE );
|
||||
vMBPortTimersDisable( );
|
||||
EXIT_CRITICAL_SECTION( );
|
||||
}
|
||||
|
||||
eMBErrorCode
|
||||
eMBASCIIReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength )
|
||||
{
|
||||
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 )
|
||||
&& ( prvucMBLRC( ( UCHAR * ) ucASCIIBuf, usRcvBufferPos ) == 0 ) )
|
||||
{
|
||||
/* Save the address field. All frames are passed to the upper layed
|
||||
* and the decision if a frame is used is done there.
|
||||
*/
|
||||
*pucRcvAddress = ucASCIIBuf[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_LRC );
|
||||
|
||||
/* Return the start of the Modbus PDU to the caller. */
|
||||
*pucFrame = ( UCHAR * ) & ucASCIIBuf[MB_SER_PDU_PDU_OFF];
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EIO;
|
||||
}
|
||||
EXIT_CRITICAL_SECTION( );
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
eMBErrorCode
|
||||
eMBASCIISend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
UCHAR usLRC;
|
||||
|
||||
ENTER_CRITICAL_SECTION( );
|
||||
/* Check if the receiver is still in idle state. If not we where too
|
||||
* 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 LRC checksum for Modbus-Serial-Line-PDU. */
|
||||
usLRC = prvucMBLRC( ( UCHAR * ) pucSndBufferCur, usSndBufferCount );
|
||||
ucASCIIBuf[usSndBufferCount++] = usLRC;
|
||||
|
||||
/* Activate the transmitter. */
|
||||
eSndState = STATE_TX_START;
|
||||
vMBPortSerialEnable( FALSE, TRUE );
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EIO;
|
||||
}
|
||||
EXIT_CRITICAL_SECTION( );
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBASCIIReceiveFSM( void )
|
||||
{
|
||||
BOOL xNeedPoll = FALSE;
|
||||
UCHAR ucByte;
|
||||
UCHAR ucResult;
|
||||
|
||||
assert( eSndState == STATE_TX_IDLE );
|
||||
|
||||
( void )xMBPortSerialGetByte( ( CHAR * ) & ucByte );
|
||||
switch ( eRcvState )
|
||||
{
|
||||
/* A new character is received. If the character is a ':' the input
|
||||
* buffer is cleared. A CR-character signals the end of the data
|
||||
* block. Other characters are part of the data block and their
|
||||
* ASCII value is converted back to a binary representation.
|
||||
*/
|
||||
case STATE_RX_RCV:
|
||||
/* Enable timer for character timeout. */
|
||||
vMBPortTimersEnable( );
|
||||
if( ucByte == ':' )
|
||||
{
|
||||
/* Empty receive buffer. */
|
||||
eBytePos = BYTE_HIGH_NIBBLE;
|
||||
usRcvBufferPos = 0;
|
||||
}
|
||||
else if( ucByte == MB_ASCII_DEFAULT_CR )
|
||||
{
|
||||
eRcvState = STATE_RX_WAIT_EOF;
|
||||
}
|
||||
else
|
||||
{
|
||||
ucResult = prvucMBCHAR2BIN( ucByte );
|
||||
switch ( eBytePos )
|
||||
{
|
||||
/* High nibble of the byte comes first. We check for
|
||||
* a buffer overflow here. */
|
||||
case BYTE_HIGH_NIBBLE:
|
||||
if( usRcvBufferPos < MB_SER_PDU_SIZE_MAX )
|
||||
{
|
||||
ucASCIIBuf[usRcvBufferPos] = ( UCHAR )( ucResult << 4 );
|
||||
eBytePos = BYTE_LOW_NIBBLE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* not handled in Modbus specification but seems
|
||||
* a resonable implementation. */
|
||||
eRcvState = STATE_RX_IDLE;
|
||||
/* Disable previously activated timer because of error state. */
|
||||
vMBPortTimersDisable( );
|
||||
}
|
||||
break;
|
||||
|
||||
case BYTE_LOW_NIBBLE:
|
||||
ucASCIIBuf[usRcvBufferPos] |= ucResult;
|
||||
usRcvBufferPos++;
|
||||
eBytePos = BYTE_HIGH_NIBBLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_RX_WAIT_EOF:
|
||||
if( ucByte == ucMBLFCharacter )
|
||||
{
|
||||
/* Disable character timeout timer because all characters are
|
||||
* received. */
|
||||
vMBPortTimersDisable( );
|
||||
/* Receiver is again in idle state. */
|
||||
eRcvState = STATE_RX_IDLE;
|
||||
|
||||
/* Notify the caller of eMBASCIIReceive that a new frame
|
||||
* was received. */
|
||||
xNeedPoll = xMBPortEventPost( EV_FRAME_RECEIVED );
|
||||
}
|
||||
else if( ucByte == ':' )
|
||||
{
|
||||
/* Empty receive buffer and back to receive state. */
|
||||
eBytePos = BYTE_HIGH_NIBBLE;
|
||||
usRcvBufferPos = 0;
|
||||
eRcvState = STATE_RX_RCV;
|
||||
|
||||
/* Enable timer for character timeout. */
|
||||
vMBPortTimersEnable( );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Frame is not okay. Delete entire frame. */
|
||||
eRcvState = STATE_RX_IDLE;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_RX_IDLE:
|
||||
if( ucByte == ':' )
|
||||
{
|
||||
/* Enable timer for character timeout. */
|
||||
vMBPortTimersEnable( );
|
||||
/* Reset the input buffers to store the frame. */
|
||||
usRcvBufferPos = 0;;
|
||||
eBytePos = BYTE_HIGH_NIBBLE;
|
||||
eRcvState = STATE_RX_RCV;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return xNeedPoll;
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBASCIITransmitFSM( void )
|
||||
{
|
||||
BOOL xNeedPoll = FALSE;
|
||||
UCHAR ucByte;
|
||||
|
||||
assert( eRcvState == STATE_RX_IDLE );
|
||||
switch ( eSndState )
|
||||
{
|
||||
/* Start of transmission. The start of a frame is defined by sending
|
||||
* the character ':'. */
|
||||
case STATE_TX_START:
|
||||
ucByte = ':';
|
||||
xMBPortSerialPutByte( ( CHAR )ucByte );
|
||||
eSndState = STATE_TX_DATA;
|
||||
eBytePos = BYTE_HIGH_NIBBLE;
|
||||
break;
|
||||
|
||||
/* Send the data block. Each data byte is encoded as a character hex
|
||||
* stream with the high nibble sent first and the low nibble sent
|
||||
* last. If all data bytes are exhausted we send a '\r' character
|
||||
* to end the transmission. */
|
||||
case STATE_TX_DATA:
|
||||
if( usSndBufferCount > 0 )
|
||||
{
|
||||
switch ( eBytePos )
|
||||
{
|
||||
case BYTE_HIGH_NIBBLE:
|
||||
ucByte = prvucMBBIN2CHAR( ( UCHAR )( *pucSndBufferCur >> 4 ) );
|
||||
xMBPortSerialPutByte( ( CHAR ) ucByte );
|
||||
eBytePos = BYTE_LOW_NIBBLE;
|
||||
break;
|
||||
|
||||
case BYTE_LOW_NIBBLE:
|
||||
ucByte = prvucMBBIN2CHAR( ( UCHAR )( *pucSndBufferCur & 0x0F ) );
|
||||
xMBPortSerialPutByte( ( CHAR )ucByte );
|
||||
pucSndBufferCur++;
|
||||
eBytePos = BYTE_HIGH_NIBBLE;
|
||||
usSndBufferCount--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
xMBPortSerialPutByte( MB_ASCII_DEFAULT_CR );
|
||||
eSndState = STATE_TX_END;
|
||||
}
|
||||
break;
|
||||
|
||||
/* Finish the frame by sending a LF character. */
|
||||
case STATE_TX_END:
|
||||
xMBPortSerialPutByte( ( CHAR )ucMBLFCharacter );
|
||||
/* We need another state to make sure that the CR character has
|
||||
* been sent. */
|
||||
eSndState = STATE_TX_NOTIFY;
|
||||
break;
|
||||
|
||||
/* Notify the task which called eMBASCIISend that the frame has
|
||||
* been sent. */
|
||||
case STATE_TX_NOTIFY:
|
||||
eSndState = STATE_TX_IDLE;
|
||||
xNeedPoll = xMBPortEventPost( EV_FRAME_SENT );
|
||||
|
||||
/* Disable transmitter. This prevents another transmit buffer
|
||||
* empty interrupt. */
|
||||
vMBPortSerialEnable( TRUE, FALSE );
|
||||
eSndState = STATE_TX_IDLE;
|
||||
break;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
return xNeedPoll;
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBASCIITimerT1SExpired( void )
|
||||
{
|
||||
switch ( eRcvState )
|
||||
{
|
||||
/* If we have a timeout we go back to the idle state and wait for
|
||||
* the next frame.
|
||||
*/
|
||||
case STATE_RX_RCV:
|
||||
case STATE_RX_WAIT_EOF:
|
||||
eRcvState = STATE_RX_IDLE;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert( ( eRcvState == STATE_RX_RCV ) || ( eRcvState == STATE_RX_WAIT_EOF ) );
|
||||
break;
|
||||
}
|
||||
vMBPortTimersDisable( );
|
||||
|
||||
/* no context switch required. */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static UCHAR
|
||||
prvucMBCHAR2BIN( UCHAR ucCharacter )
|
||||
{
|
||||
if( ( ucCharacter >= '0' ) && ( ucCharacter <= '9' ) )
|
||||
{
|
||||
return ( UCHAR )( ucCharacter - '0' );
|
||||
}
|
||||
else if( ( ucCharacter >= 'A' ) && ( ucCharacter <= 'F' ) )
|
||||
{
|
||||
return ( UCHAR )( ucCharacter - 'A' + 0x0A );
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
static UCHAR
|
||||
prvucMBBIN2CHAR( UCHAR ucByte )
|
||||
{
|
||||
if( ucByte <= 0x09 )
|
||||
{
|
||||
return ( UCHAR )( '0' + ucByte );
|
||||
}
|
||||
else if( ( ucByte >= 0x0A ) && ( ucByte <= 0x0F ) )
|
||||
{
|
||||
return ( UCHAR )( ucByte - 0x0A + 'A' );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Programming error. */
|
||||
assert( 0 );
|
||||
}
|
||||
return '0';
|
||||
}
|
||||
|
||||
|
||||
static UCHAR
|
||||
prvucMBLRC( UCHAR * pucFrame, USHORT usLen )
|
||||
{
|
||||
UCHAR ucLRC = 0; /* LRC char initialized */
|
||||
|
||||
while( usLen-- )
|
||||
{
|
||||
ucLRC += *pucFrame++; /* Add buffer byte without carry */
|
||||
}
|
||||
|
||||
/* Return twos complement */
|
||||
ucLRC = ( UCHAR ) ( -( ( CHAR ) ucLRC ) );
|
||||
return ucLRC;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.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: mbascii.h,v 1.8 2006/12/07 22:10:34 wolti Exp $
|
||||
*/
|
||||
|
||||
#ifndef _MB_ASCII_H
|
||||
#define _MB_ASCII_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if MB_SLAVE_ASCII_ENABLED > 0
|
||||
eMBErrorCode eMBASCIIInit( UCHAR slaveAddress, UCHAR ucPort,
|
||||
ULONG ulBaudRate, eMBParity eParity );
|
||||
void eMBASCIIStart( void );
|
||||
void eMBASCIIStop( void );
|
||||
|
||||
eMBErrorCode eMBASCIIReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame,
|
||||
USHORT * pusLength );
|
||||
eMBErrorCode eMBASCIISend( UCHAR slaveAddress, const UCHAR * pucFrame,
|
||||
USHORT usLength );
|
||||
BOOL xMBASCIIReceiveFSM( void );
|
||||
BOOL xMBASCIITransmitFSM( void );
|
||||
BOOL xMBASCIITimerT1SExpired( void );
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,390 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
|
||||
* 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_m.c,v 1.60 2013/10/12 15:10:12 Armink Add Master Functions
|
||||
*/
|
||||
|
||||
/* ----------------------- System includes ----------------------------------*/
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
|
||||
/* ----------------------- Platform includes --------------------------------*/
|
||||
#include "port.h"
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mb_m.h"
|
||||
#include "mbframe.h"
|
||||
#include "mbproto.h"
|
||||
#include "mbconfig.h"
|
||||
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
#define MB_PDU_REQ_READ_ADDR_OFF ( MB_PDU_DATA_OFF + 0 )
|
||||
#define MB_PDU_REQ_READ_COILCNT_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||
#define MB_PDU_REQ_READ_SIZE ( 4 )
|
||||
#define MB_PDU_FUNC_READ_COILCNT_OFF ( MB_PDU_DATA_OFF + 0 )
|
||||
#define MB_PDU_FUNC_READ_VALUES_OFF ( MB_PDU_DATA_OFF + 1 )
|
||||
#define MB_PDU_FUNC_READ_SIZE_MIN ( 1 )
|
||||
|
||||
#define MB_PDU_REQ_WRITE_ADDR_OFF ( MB_PDU_DATA_OFF )
|
||||
#define MB_PDU_REQ_WRITE_VALUE_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||
#define MB_PDU_REQ_WRITE_SIZE ( 4 )
|
||||
#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_REQ_WRITE_MUL_ADDR_OFF ( MB_PDU_DATA_OFF )
|
||||
#define MB_PDU_REQ_WRITE_MUL_COILCNT_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||
#define MB_PDU_REQ_WRITE_MUL_BYTECNT_OFF ( MB_PDU_DATA_OFF + 4 )
|
||||
#define MB_PDU_REQ_WRITE_MUL_VALUES_OFF ( MB_PDU_DATA_OFF + 5 )
|
||||
#define MB_PDU_REQ_WRITE_MUL_SIZE_MIN ( 5 )
|
||||
#define MB_PDU_REQ_WRITE_MUL_COILCNT_MAX ( 0x07B0 )
|
||||
#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_SIZE ( 5 )
|
||||
|
||||
/* ----------------------- Static functions ---------------------------------*/
|
||||
eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
|
||||
#if MB_FUNC_READ_COILS_ENABLED > 0
|
||||
|
||||
/**
|
||||
* This function will request read coil.
|
||||
*
|
||||
* @param ucSndAddr salve address
|
||||
* @param usCoilAddr coil start address
|
||||
* @param usNCoils coil total number
|
||||
* @param lTimeOut timeout (-1 will waiting forever)
|
||||
*
|
||||
* @return error code
|
||||
*/
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqReadCoils( UCHAR ucSndAddr, USHORT usCoilAddr, USHORT usNCoils ,LONG lTimeOut )
|
||||
{
|
||||
UCHAR *ucMBFrame;
|
||||
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
|
||||
|
||||
if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
|
||||
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
|
||||
else
|
||||
{
|
||||
vMBMasterGetPDUSndBuf(&ucMBFrame);
|
||||
vMBMasterSetDestAddress(ucSndAddr);
|
||||
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_READ_COILS;
|
||||
ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] = usCoilAddr >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] = usCoilAddr;
|
||||
ucMBFrame[MB_PDU_REQ_READ_COILCNT_OFF ] = usNCoils >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_READ_COILCNT_OFF + 1] = usNCoils;
|
||||
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
|
||||
eErrStatus = eMBMasterWaitRequestFinish( );
|
||||
|
||||
}
|
||||
return eErrStatus;
|
||||
}
|
||||
|
||||
eMBException
|
||||
eMBMasterFuncReadCoils( UCHAR * pucFrame, USHORT * usLen )
|
||||
{
|
||||
UCHAR *ucMBFrame;
|
||||
USHORT usRegAddress;
|
||||
USHORT usCoilCount;
|
||||
UCHAR ucByteCount;
|
||||
|
||||
eMBException eStatus = MB_EX_NONE;
|
||||
eMBErrorCode eRegStatus;
|
||||
|
||||
/* If this request is broadcast, and it's read mode. This request don't need execute. */
|
||||
if ( xMBMasterRequestIsBroadcast() )
|
||||
{
|
||||
eStatus = MB_EX_NONE;
|
||||
}
|
||||
else if ( *usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READ_SIZE_MIN )
|
||||
{
|
||||
vMBMasterGetPDUSndBuf(&ucMBFrame);
|
||||
usRegAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] << 8 );
|
||||
usRegAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] );
|
||||
usRegAddress++;
|
||||
|
||||
usCoilCount = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_COILCNT_OFF] << 8 );
|
||||
usCoilCount |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_COILCNT_OFF + 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 )
|
||||
{
|
||||
ucByteCount = ( UCHAR )( usCoilCount / 8 + 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
ucByteCount = ( UCHAR )( usCoilCount / 8 );
|
||||
}
|
||||
|
||||
/* Check if the number of registers to read is valid. If not
|
||||
* return Modbus illegal data value exception.
|
||||
*/
|
||||
if( ( usCoilCount >= 1 ) &&
|
||||
( ucByteCount == pucFrame[MB_PDU_FUNC_READ_COILCNT_OFF] ) )
|
||||
{
|
||||
/* Make callback to fill the buffer. */
|
||||
eRegStatus = eMBMasterRegCoilsCB( &pucFrame[MB_PDU_FUNC_READ_VALUES_OFF], usRegAddress, usCoilCount, MB_REG_READ );
|
||||
|
||||
/* 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 read coil register request because the length
|
||||
* is incorrect. */
|
||||
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MB_FUNC_WRITE_COIL_ENABLED > 0
|
||||
|
||||
/**
|
||||
* This function will request write one coil.
|
||||
*
|
||||
* @param ucSndAddr salve address
|
||||
* @param usCoilAddr coil start address
|
||||
* @param usCoilData data to be written
|
||||
* @param lTimeOut timeout (-1 will waiting forever)
|
||||
*
|
||||
* @return error code
|
||||
*
|
||||
* @see eMBMasterReqWriteMultipleCoils
|
||||
*/
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqWriteCoil( UCHAR ucSndAddr, USHORT usCoilAddr, USHORT usCoilData, LONG lTimeOut )
|
||||
{
|
||||
UCHAR *ucMBFrame;
|
||||
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
|
||||
|
||||
if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
|
||||
else if ( ( usCoilData != 0xFF00 ) && ( usCoilData != 0x0000 ) ) eErrStatus = MB_MRE_ILL_ARG;
|
||||
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
|
||||
else
|
||||
{
|
||||
vMBMasterGetPDUSndBuf(&ucMBFrame);
|
||||
vMBMasterSetDestAddress(ucSndAddr);
|
||||
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_WRITE_SINGLE_COIL;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_ADDR_OFF] = usCoilAddr >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_ADDR_OFF + 1] = usCoilAddr;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF ] = usCoilData >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF + 1] = usCoilData;
|
||||
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_SIZE );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
|
||||
eErrStatus = eMBMasterWaitRequestFinish( );
|
||||
}
|
||||
return eErrStatus;
|
||||
}
|
||||
|
||||
eMBException
|
||||
eMBMasterFuncWriteCoil( 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 =
|
||||
eMBMasterRegCoilsCB( &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
|
||||
|
||||
/**
|
||||
* This function will request write multiple coils.
|
||||
*
|
||||
* @param ucSndAddr salve address
|
||||
* @param usCoilAddr coil start address
|
||||
* @param usNCoils coil total number
|
||||
* @param usCoilData data to be written
|
||||
* @param lTimeOut timeout (-1 will waiting forever)
|
||||
*
|
||||
* @return error code
|
||||
*
|
||||
* @see eMBMasterReqWriteCoil
|
||||
*/
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqWriteMultipleCoils( UCHAR ucSndAddr,
|
||||
USHORT usCoilAddr, USHORT usNCoils, UCHAR * pucDataBuffer, LONG lTimeOut)
|
||||
{
|
||||
UCHAR *ucMBFrame;
|
||||
USHORT usRegIndex = 0;
|
||||
UCHAR ucByteCount;
|
||||
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
|
||||
|
||||
if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
|
||||
else if ( usNCoils > MB_PDU_REQ_WRITE_MUL_COILCNT_MAX ) eErrStatus = MB_MRE_ILL_ARG;
|
||||
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
|
||||
else
|
||||
{
|
||||
vMBMasterGetPDUSndBuf(&ucMBFrame);
|
||||
vMBMasterSetDestAddress(ucSndAddr);
|
||||
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_WRITE_MULTIPLE_COILS;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF] = usCoilAddr >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF + 1] = usCoilAddr;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_MUL_COILCNT_OFF] = usNCoils >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_MUL_COILCNT_OFF + 1] = usNCoils ;
|
||||
if( ( usNCoils & 0x0007 ) != 0 )
|
||||
{
|
||||
ucByteCount = ( UCHAR )( usNCoils / 8 + 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
ucByteCount = ( UCHAR )( usNCoils / 8 );
|
||||
}
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_MUL_BYTECNT_OFF] = ucByteCount;
|
||||
ucMBFrame += MB_PDU_REQ_WRITE_MUL_VALUES_OFF;
|
||||
while( ucByteCount > usRegIndex)
|
||||
{
|
||||
*ucMBFrame++ = pucDataBuffer[usRegIndex++];
|
||||
}
|
||||
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_MUL_SIZE_MIN + ucByteCount );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
|
||||
eErrStatus = eMBMasterWaitRequestFinish( );
|
||||
}
|
||||
return eErrStatus;
|
||||
}
|
||||
|
||||
eMBException
|
||||
eMBMasterFuncWriteMultipleCoils( UCHAR * pucFrame, USHORT * usLen )
|
||||
{
|
||||
USHORT usRegAddress;
|
||||
USHORT usCoilCnt;
|
||||
UCHAR ucByteCount;
|
||||
UCHAR ucByteCountVerify;
|
||||
UCHAR *ucMBFrame;
|
||||
|
||||
eMBException eStatus = MB_EX_NONE;
|
||||
eMBErrorCode eRegStatus;
|
||||
|
||||
/* If this request is broadcast, the *usLen is not need check. */
|
||||
if( ( *usLen == MB_PDU_FUNC_WRITE_MUL_SIZE ) || xMBMasterRequestIsBroadcast() )
|
||||
{
|
||||
vMBMasterGetPDUSndBuf(&ucMBFrame);
|
||||
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 = ucMBFrame[MB_PDU_REQ_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 ) && ( ucByteCountVerify == ucByteCount ) )
|
||||
{
|
||||
eRegStatus =
|
||||
eMBMasterRegCoilsCB( &ucMBFrame[MB_PDU_REQ_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
|
||||
{
|
||||
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
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.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 $
|
||||
*/
|
||||
@@ -1,133 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.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.
|
||||
*
|
||||
*/
|
||||
|
||||
/* ----------------------- 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
|
||||
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
|
||||
* 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: mbfuncdisc_m.c,v 1.60 2013/10/15 8:48:20 Armink Add Master Functions Exp $
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* ----------------------- System includes ----------------------------------*/
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
|
||||
/* ----------------------- Platform includes --------------------------------*/
|
||||
#include "port.h"
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mb_m.h"
|
||||
#include "mbframe.h"
|
||||
#include "mbproto.h"
|
||||
#include "mbconfig.h"
|
||||
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
#define MB_PDU_REQ_READ_ADDR_OFF ( MB_PDU_DATA_OFF + 0 )
|
||||
#define MB_PDU_REQ_READ_DISCCNT_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||
#define MB_PDU_REQ_READ_SIZE ( 4 )
|
||||
#define MB_PDU_FUNC_READ_DISCCNT_OFF ( MB_PDU_DATA_OFF + 0 )
|
||||
#define MB_PDU_FUNC_READ_VALUES_OFF ( MB_PDU_DATA_OFF + 1 )
|
||||
#define MB_PDU_FUNC_READ_SIZE_MIN ( 1 )
|
||||
|
||||
/* ----------------------- Static functions ---------------------------------*/
|
||||
eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
|
||||
#if MB_FUNC_READ_DISCRETE_INPUTS_ENABLED > 0
|
||||
|
||||
/**
|
||||
* This function will request read discrete inputs.
|
||||
*
|
||||
* @param ucSndAddr salve address
|
||||
* @param usDiscreteAddr discrete start address
|
||||
* @param usNDiscreteIn discrete total number
|
||||
* @param lTimeOut timeout (-1 will waiting forever)
|
||||
*
|
||||
* @return error code
|
||||
*/
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqReadDiscreteInputs( UCHAR ucSndAddr, USHORT usDiscreteAddr, USHORT usNDiscreteIn, LONG lTimeOut )
|
||||
{
|
||||
UCHAR *ucMBFrame;
|
||||
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
|
||||
|
||||
if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
|
||||
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
|
||||
else
|
||||
{
|
||||
vMBMasterGetPDUSndBuf(&ucMBFrame);
|
||||
vMBMasterSetDestAddress(ucSndAddr);
|
||||
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_READ_DISCRETE_INPUTS;
|
||||
ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] = usDiscreteAddr >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] = usDiscreteAddr;
|
||||
ucMBFrame[MB_PDU_REQ_READ_DISCCNT_OFF ] = usNDiscreteIn >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_READ_DISCCNT_OFF + 1] = usNDiscreteIn;
|
||||
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
|
||||
eErrStatus = eMBMasterWaitRequestFinish( );
|
||||
}
|
||||
return eErrStatus;
|
||||
}
|
||||
|
||||
eMBException
|
||||
eMBMasterFuncReadDiscreteInputs( UCHAR * pucFrame, USHORT * usLen )
|
||||
{
|
||||
USHORT usRegAddress;
|
||||
USHORT usDiscreteCnt;
|
||||
UCHAR ucNBytes;
|
||||
UCHAR *ucMBFrame;
|
||||
|
||||
eMBException eStatus = MB_EX_NONE;
|
||||
eMBErrorCode eRegStatus;
|
||||
|
||||
/* If this request is broadcast, and it's read mode. This request don't need execute. */
|
||||
if ( xMBMasterRequestIsBroadcast() )
|
||||
{
|
||||
eStatus = MB_EX_NONE;
|
||||
}
|
||||
else if( *usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READ_SIZE_MIN )
|
||||
{
|
||||
vMBMasterGetPDUSndBuf(&ucMBFrame);
|
||||
usRegAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] << 8 );
|
||||
usRegAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] );
|
||||
usRegAddress++;
|
||||
|
||||
usDiscreteCnt = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_DISCCNT_OFF] << 8 );
|
||||
usDiscreteCnt |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_DISCCNT_OFF + 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 );
|
||||
}
|
||||
|
||||
/* Check if the number of registers to read is valid. If not
|
||||
* return Modbus illegal data value exception.
|
||||
*/
|
||||
if ((usDiscreteCnt >= 1) && ucNBytes == pucFrame[MB_PDU_FUNC_READ_DISCCNT_OFF])
|
||||
{
|
||||
/* Make callback to fill the buffer. */
|
||||
eRegStatus = eMBMasterRegDiscreteCB( &pucFrame[MB_PDU_FUNC_READ_VALUES_OFF], usRegAddress, usDiscreteCnt );
|
||||
|
||||
/* 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 read coil register request because the length
|
||||
* is incorrect. */
|
||||
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,455 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
|
||||
* 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_m.c,v 1.60 2013/09/02 14:13:40 Armink Add Master Functions Exp $
|
||||
*/
|
||||
|
||||
/* ----------------------- System includes ----------------------------------*/
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
|
||||
/* ----------------------- Platform includes --------------------------------*/
|
||||
#include "port.h"
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mb_m.h"
|
||||
#include "mbframe.h"
|
||||
#include "mbproto.h"
|
||||
#include "mbconfig.h"
|
||||
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
#define MB_PDU_REQ_READ_ADDR_OFF ( MB_PDU_DATA_OFF + 0 )
|
||||
#define MB_PDU_REQ_READ_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||
#define MB_PDU_REQ_READ_SIZE ( 4 )
|
||||
#define MB_PDU_FUNC_READ_REGCNT_MAX ( 0x007D )
|
||||
#define MB_PDU_FUNC_READ_BYTECNT_OFF ( MB_PDU_DATA_OFF + 0 )
|
||||
#define MB_PDU_FUNC_READ_VALUES_OFF ( MB_PDU_DATA_OFF + 1 )
|
||||
#define MB_PDU_FUNC_READ_SIZE_MIN ( 1 )
|
||||
|
||||
#define MB_PDU_REQ_WRITE_ADDR_OFF ( MB_PDU_DATA_OFF + 0)
|
||||
#define MB_PDU_REQ_WRITE_VALUE_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||
#define MB_PDU_REQ_WRITE_SIZE ( 4 )
|
||||
#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_REQ_WRITE_MUL_ADDR_OFF ( MB_PDU_DATA_OFF + 0 )
|
||||
#define MB_PDU_REQ_WRITE_MUL_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||
#define MB_PDU_REQ_WRITE_MUL_BYTECNT_OFF ( MB_PDU_DATA_OFF + 4 )
|
||||
#define MB_PDU_REQ_WRITE_MUL_VALUES_OFF ( MB_PDU_DATA_OFF + 5 )
|
||||
#define MB_PDU_REQ_WRITE_MUL_SIZE_MIN ( 5 )
|
||||
#define MB_PDU_REQ_WRITE_MUL_REGCNT_MAX ( 0x0078 )
|
||||
#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_SIZE ( 4 )
|
||||
|
||||
#define MB_PDU_REQ_READWRITE_READ_ADDR_OFF ( MB_PDU_DATA_OFF + 0 )
|
||||
#define MB_PDU_REQ_READWRITE_READ_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||
#define MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF ( MB_PDU_DATA_OFF + 4 )
|
||||
#define MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF ( MB_PDU_DATA_OFF + 6 )
|
||||
#define MB_PDU_REQ_READWRITE_WRITE_BYTECNT_OFF ( MB_PDU_DATA_OFF + 8 )
|
||||
#define MB_PDU_REQ_READWRITE_WRITE_VALUES_OFF ( MB_PDU_DATA_OFF + 9 )
|
||||
#define MB_PDU_REQ_READWRITE_SIZE_MIN ( 9 )
|
||||
#define MB_PDU_FUNC_READWRITE_READ_BYTECNT_OFF ( MB_PDU_DATA_OFF + 0 )
|
||||
#define MB_PDU_FUNC_READWRITE_READ_VALUES_OFF ( MB_PDU_DATA_OFF + 1 )
|
||||
#define MB_PDU_FUNC_READWRITE_SIZE_MIN ( 1 )
|
||||
|
||||
/* ----------------------- Static functions ---------------------------------*/
|
||||
eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
|
||||
#if MB_FUNC_WRITE_HOLDING_ENABLED > 0
|
||||
|
||||
/**
|
||||
* This function will request write holding register.
|
||||
*
|
||||
* @param ucSndAddr salve address
|
||||
* @param usRegAddr register start address
|
||||
* @param usRegData register data to be written
|
||||
* @param lTimeOut timeout (-1 will waiting forever)
|
||||
*
|
||||
* @return error code
|
||||
*/
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqWriteHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usRegData, LONG lTimeOut )
|
||||
{
|
||||
UCHAR *ucMBFrame;
|
||||
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
|
||||
|
||||
if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
|
||||
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
|
||||
else
|
||||
{
|
||||
vMBMasterGetPDUSndBuf(&ucMBFrame);
|
||||
vMBMasterSetDestAddress(ucSndAddr);
|
||||
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_WRITE_REGISTER;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_ADDR_OFF] = usRegAddr >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_ADDR_OFF + 1] = usRegAddr;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF] = usRegData >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF + 1] = usRegData ;
|
||||
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_SIZE );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
|
||||
eErrStatus = eMBMasterWaitRequestFinish( );
|
||||
}
|
||||
return eErrStatus;
|
||||
}
|
||||
|
||||
eMBException
|
||||
eMBMasterFuncWriteHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
|
||||
{
|
||||
USHORT usRegAddress;
|
||||
eMBException eStatus = MB_EX_NONE;
|
||||
eMBErrorCode eRegStatus;
|
||||
|
||||
if( *usLen == ( MB_PDU_SIZE_MIN + MB_PDU_FUNC_WRITE_SIZE ) )
|
||||
{
|
||||
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 = eMBMasterRegHoldingCB( &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
|
||||
|
||||
/**
|
||||
* This function will request write multiple holding register.
|
||||
*
|
||||
* @param ucSndAddr salve address
|
||||
* @param usRegAddr register start address
|
||||
* @param usNRegs register total number
|
||||
* @param pusDataBuffer data to be written
|
||||
* @param lTimeOut timeout (-1 will waiting forever)
|
||||
*
|
||||
* @return error code
|
||||
*/
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqWriteMultipleHoldingRegister( UCHAR ucSndAddr,
|
||||
USHORT usRegAddr, USHORT usNRegs, USHORT * pusDataBuffer, LONG lTimeOut )
|
||||
{
|
||||
UCHAR *ucMBFrame;
|
||||
USHORT usRegIndex = 0;
|
||||
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
|
||||
|
||||
if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
|
||||
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
|
||||
else
|
||||
{
|
||||
vMBMasterGetPDUSndBuf(&ucMBFrame);
|
||||
vMBMasterSetDestAddress(ucSndAddr);
|
||||
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_WRITE_MULTIPLE_REGISTERS;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF] = usRegAddr >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF + 1] = usRegAddr;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_MUL_REGCNT_OFF] = usNRegs >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_MUL_REGCNT_OFF + 1] = usNRegs ;
|
||||
ucMBFrame[MB_PDU_REQ_WRITE_MUL_BYTECNT_OFF] = usNRegs * 2;
|
||||
ucMBFrame += MB_PDU_REQ_WRITE_MUL_VALUES_OFF;
|
||||
while( usNRegs > usRegIndex)
|
||||
{
|
||||
*ucMBFrame++ = pusDataBuffer[usRegIndex] >> 8;
|
||||
*ucMBFrame++ = pusDataBuffer[usRegIndex++] ;
|
||||
}
|
||||
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_MUL_SIZE_MIN + 2*usNRegs );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
|
||||
eErrStatus = eMBMasterWaitRequestFinish( );
|
||||
}
|
||||
return eErrStatus;
|
||||
}
|
||||
|
||||
eMBException
|
||||
eMBMasterFuncWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
|
||||
{
|
||||
UCHAR *ucMBFrame;
|
||||
USHORT usRegAddress;
|
||||
USHORT usRegCount;
|
||||
UCHAR ucRegByteCount;
|
||||
|
||||
eMBException eStatus = MB_EX_NONE;
|
||||
eMBErrorCode eRegStatus;
|
||||
|
||||
/* If this request is broadcast, the *usLen is not need check. */
|
||||
if( ( *usLen == MB_PDU_SIZE_MIN + MB_PDU_FUNC_WRITE_MUL_SIZE ) || xMBMasterRequestIsBroadcast() )
|
||||
{
|
||||
vMBMasterGetPDUSndBuf(&ucMBFrame);
|
||||
usRegAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF] << 8 );
|
||||
usRegAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF + 1] );
|
||||
usRegAddress++;
|
||||
|
||||
usRegCount = ( USHORT )( ucMBFrame[MB_PDU_REQ_WRITE_MUL_REGCNT_OFF] << 8 );
|
||||
usRegCount |= ( USHORT )( ucMBFrame[MB_PDU_REQ_WRITE_MUL_REGCNT_OFF + 1] );
|
||||
|
||||
ucRegByteCount = ucMBFrame[MB_PDU_REQ_WRITE_MUL_BYTECNT_OFF];
|
||||
|
||||
if( ucRegByteCount == 2 * usRegCount )
|
||||
{
|
||||
/* Make callback to update the register values. */
|
||||
eRegStatus =
|
||||
eMBMasterRegHoldingCB( &ucMBFrame[MB_PDU_REQ_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
|
||||
{
|
||||
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
|
||||
|
||||
/**
|
||||
* This function will request read holding register.
|
||||
*
|
||||
* @param ucSndAddr salve address
|
||||
* @param usRegAddr register start address
|
||||
* @param usNRegs register total number
|
||||
* @param lTimeOut timeout (-1 will waiting forever)
|
||||
*
|
||||
* @return error code
|
||||
*/
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqReadHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs, LONG lTimeOut )
|
||||
{
|
||||
UCHAR *ucMBFrame;
|
||||
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
|
||||
|
||||
if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
|
||||
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
|
||||
else
|
||||
{
|
||||
vMBMasterGetPDUSndBuf(&ucMBFrame);
|
||||
vMBMasterSetDestAddress(ucSndAddr);
|
||||
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_READ_HOLDING_REGISTER;
|
||||
ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] = usRegAddr >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] = usRegAddr;
|
||||
ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF] = usNRegs >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF + 1] = usNRegs;
|
||||
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
|
||||
eErrStatus = eMBMasterWaitRequestFinish( );
|
||||
}
|
||||
return eErrStatus;
|
||||
}
|
||||
|
||||
eMBException
|
||||
eMBMasterFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
|
||||
{
|
||||
UCHAR *ucMBFrame;
|
||||
USHORT usRegAddress;
|
||||
USHORT usRegCount;
|
||||
|
||||
eMBException eStatus = MB_EX_NONE;
|
||||
eMBErrorCode eRegStatus;
|
||||
|
||||
/* If this request is broadcast, and it's read mode. This request don't need execute. */
|
||||
if ( xMBMasterRequestIsBroadcast() )
|
||||
{
|
||||
eStatus = MB_EX_NONE;
|
||||
}
|
||||
else if( *usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READ_SIZE_MIN )
|
||||
{
|
||||
vMBMasterGetPDUSndBuf(&ucMBFrame);
|
||||
usRegAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] << 8 );
|
||||
usRegAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] );
|
||||
usRegAddress++;
|
||||
|
||||
usRegCount = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF] << 8 );
|
||||
usRegCount |= ( USHORT )( ucMBFrame[MB_PDU_REQ_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 ) && ( 2 * usRegCount == pucFrame[MB_PDU_FUNC_READ_BYTECNT_OFF] ) )
|
||||
{
|
||||
/* Make callback to fill the buffer. */
|
||||
eRegStatus = eMBMasterRegHoldingCB( &pucFrame[MB_PDU_FUNC_READ_VALUES_OFF], usRegAddress, usRegCount, MB_REG_READ );
|
||||
/* 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 request because the length is incorrect. */
|
||||
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if MB_FUNC_READWRITE_HOLDING_ENABLED > 0
|
||||
|
||||
/**
|
||||
* This function will request read and write holding register.
|
||||
*
|
||||
* @param ucSndAddr salve address
|
||||
* @param usReadRegAddr read register start address
|
||||
* @param usNReadRegs read register total number
|
||||
* @param pusDataBuffer data to be written
|
||||
* @param usWriteRegAddr write register start address
|
||||
* @param usNWriteRegs write register total number
|
||||
* @param lTimeOut timeout (-1 will waiting forever)
|
||||
*
|
||||
* @return error code
|
||||
*/
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqReadWriteMultipleHoldingRegister( UCHAR ucSndAddr,
|
||||
USHORT usReadRegAddr, USHORT usNReadRegs, USHORT * pusDataBuffer,
|
||||
USHORT usWriteRegAddr, USHORT usNWriteRegs, LONG lTimeOut )
|
||||
{
|
||||
UCHAR *ucMBFrame;
|
||||
USHORT usRegIndex = 0;
|
||||
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
|
||||
|
||||
if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
|
||||
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
|
||||
else
|
||||
{
|
||||
vMBMasterGetPDUSndBuf(&ucMBFrame);
|
||||
vMBMasterSetDestAddress(ucSndAddr);
|
||||
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_READWRITE_MULTIPLE_REGISTERS;
|
||||
ucMBFrame[MB_PDU_REQ_READWRITE_READ_ADDR_OFF] = usReadRegAddr >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_READWRITE_READ_ADDR_OFF + 1] = usReadRegAddr;
|
||||
ucMBFrame[MB_PDU_REQ_READWRITE_READ_REGCNT_OFF] = usNReadRegs >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_READWRITE_READ_REGCNT_OFF + 1] = usNReadRegs ;
|
||||
ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF] = usWriteRegAddr >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF + 1] = usWriteRegAddr;
|
||||
ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF] = usNWriteRegs >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF + 1] = usNWriteRegs ;
|
||||
ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_BYTECNT_OFF] = usNWriteRegs * 2;
|
||||
ucMBFrame += MB_PDU_REQ_READWRITE_WRITE_VALUES_OFF;
|
||||
while( usNWriteRegs > usRegIndex)
|
||||
{
|
||||
*ucMBFrame++ = pusDataBuffer[usRegIndex] >> 8;
|
||||
*ucMBFrame++ = pusDataBuffer[usRegIndex++] ;
|
||||
}
|
||||
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READWRITE_SIZE_MIN + 2*usNWriteRegs );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
|
||||
eErrStatus = eMBMasterWaitRequestFinish( );
|
||||
}
|
||||
return eErrStatus;
|
||||
}
|
||||
|
||||
eMBException
|
||||
eMBMasterFuncReadWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
|
||||
{
|
||||
USHORT usRegReadAddress;
|
||||
USHORT usRegReadCount;
|
||||
USHORT usRegWriteAddress;
|
||||
USHORT usRegWriteCount;
|
||||
UCHAR *ucMBFrame;
|
||||
|
||||
eMBException eStatus = MB_EX_NONE;
|
||||
eMBErrorCode eRegStatus;
|
||||
|
||||
/* If this request is broadcast, and it's read mode. This request don't need execute. */
|
||||
if ( xMBMasterRequestIsBroadcast() )
|
||||
{
|
||||
eStatus = MB_EX_NONE;
|
||||
}
|
||||
else if( *usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READWRITE_SIZE_MIN )
|
||||
{
|
||||
vMBMasterGetPDUSndBuf(&ucMBFrame);
|
||||
usRegReadAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_READ_ADDR_OFF] << 8U );
|
||||
usRegReadAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_READ_ADDR_OFF + 1] );
|
||||
usRegReadAddress++;
|
||||
|
||||
usRegReadCount = ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_READ_REGCNT_OFF] << 8U );
|
||||
usRegReadCount |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_READ_REGCNT_OFF + 1] );
|
||||
|
||||
usRegWriteAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF] << 8U );
|
||||
usRegWriteAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF + 1] );
|
||||
usRegWriteAddress++;
|
||||
|
||||
usRegWriteCount = ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF] << 8U );
|
||||
usRegWriteCount |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF + 1] );
|
||||
|
||||
if( ( 2 * usRegReadCount ) == pucFrame[MB_PDU_FUNC_READWRITE_READ_BYTECNT_OFF] )
|
||||
{
|
||||
/* Make callback to update the register values. */
|
||||
eRegStatus = eMBMasterRegHoldingCB( &ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_VALUES_OFF],
|
||||
usRegWriteAddress, usRegWriteCount, MB_REG_WRITE );
|
||||
|
||||
if( eRegStatus == MB_ENOERR )
|
||||
{
|
||||
/* Make the read callback. */
|
||||
eRegStatus = eMBMasterRegHoldingCB(&pucFrame[MB_PDU_FUNC_READWRITE_READ_VALUES_OFF],
|
||||
usRegReadAddress, usRegReadCount, MB_REG_READ);
|
||||
}
|
||||
if( eRegStatus != MB_ENOERR )
|
||||
{
|
||||
eStatus = prveMBError2Exception( eRegStatus );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||
}
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.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
|
||||
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
|
||||
* 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_m.c,v 1.60 2013/10/12 14:23:40 Armink Add Master Functions Exp $
|
||||
*/
|
||||
|
||||
/* ----------------------- System includes ----------------------------------*/
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
|
||||
/* ----------------------- Platform includes --------------------------------*/
|
||||
#include "port.h"
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mb_m.h"
|
||||
#include "mbframe.h"
|
||||
#include "mbproto.h"
|
||||
#include "mbconfig.h"
|
||||
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
#define MB_PDU_REQ_READ_ADDR_OFF ( MB_PDU_DATA_OFF + 0 )
|
||||
#define MB_PDU_REQ_READ_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 )
|
||||
#define MB_PDU_REQ_READ_SIZE ( 4 )
|
||||
#define MB_PDU_FUNC_READ_BYTECNT_OFF ( MB_PDU_DATA_OFF + 0 )
|
||||
#define MB_PDU_FUNC_READ_VALUES_OFF ( MB_PDU_DATA_OFF + 1 )
|
||||
#define MB_PDU_FUNC_READ_SIZE_MIN ( 1 )
|
||||
|
||||
#define MB_PDU_FUNC_READ_RSP_BYTECNT_OFF ( MB_PDU_DATA_OFF )
|
||||
|
||||
/* ----------------------- Static functions ---------------------------------*/
|
||||
eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
|
||||
#if MB_FUNC_READ_INPUT_ENABLED > 0
|
||||
|
||||
/**
|
||||
* This function will request read input register.
|
||||
*
|
||||
* @param ucSndAddr salve address
|
||||
* @param usRegAddr register start address
|
||||
* @param usNRegs register total number
|
||||
* @param lTimeOut timeout (-1 will waiting forever)
|
||||
*
|
||||
* @return error code
|
||||
*/
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqReadInputRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs, LONG lTimeOut )
|
||||
{
|
||||
UCHAR *ucMBFrame;
|
||||
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
|
||||
|
||||
if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
|
||||
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
|
||||
else
|
||||
{
|
||||
vMBMasterGetPDUSndBuf(&ucMBFrame);
|
||||
vMBMasterSetDestAddress(ucSndAddr);
|
||||
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_READ_INPUT_REGISTER;
|
||||
ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] = usRegAddr >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] = usRegAddr;
|
||||
ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF] = usNRegs >> 8;
|
||||
ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF + 1] = usNRegs;
|
||||
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE );
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
|
||||
eErrStatus = eMBMasterWaitRequestFinish( );
|
||||
}
|
||||
return eErrStatus;
|
||||
}
|
||||
|
||||
eMBException
|
||||
eMBMasterFuncReadInputRegister( UCHAR * pucFrame, USHORT * usLen )
|
||||
{
|
||||
UCHAR *ucMBFrame;
|
||||
USHORT usRegAddress;
|
||||
USHORT usRegCount;
|
||||
|
||||
eMBException eStatus = MB_EX_NONE;
|
||||
eMBErrorCode eRegStatus;
|
||||
|
||||
/* If this request is broadcast, and it's read mode. This request don't need execute. */
|
||||
if ( xMBMasterRequestIsBroadcast() )
|
||||
{
|
||||
eStatus = MB_EX_NONE;
|
||||
}
|
||||
else if( *usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READ_SIZE_MIN )
|
||||
{
|
||||
vMBMasterGetPDUSndBuf(&ucMBFrame);
|
||||
usRegAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] << 8 );
|
||||
usRegAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] );
|
||||
usRegAddress++;
|
||||
|
||||
usRegCount = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF] << 8 );
|
||||
usRegCount |= ( USHORT )( ucMBFrame[MB_PDU_REQ_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 ) && ( 2 * usRegCount == pucFrame[MB_PDU_FUNC_READ_BYTECNT_OFF] ) )
|
||||
{
|
||||
/* Make callback to fill the buffer. */
|
||||
eRegStatus = eMBMasterRegInputCB( &pucFrame[MB_PDU_FUNC_READ_VALUES_OFF], usRegAddress, usRegCount );
|
||||
/* 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 request because the length is incorrect. */
|
||||
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.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
|
||||
@@ -1,141 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.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;
|
||||
|
||||
RT_ASSERT( ucNBits <= 8 );
|
||||
RT_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;
|
||||
}
|
||||
@@ -1,416 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
|
||||
* 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_m.h,v 1.60 2013/09/03 10:20:05 Armink Add Master Functions $
|
||||
*/
|
||||
|
||||
#ifndef _MB_M_H
|
||||
#define _MB_M_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \defgroup modbus Modbus
|
||||
* \code #include "mb_m.h" \endcode
|
||||
*
|
||||
* This module defines the interface for the application. It contains
|
||||
* the basic functions and types required to use the Modbus Master protocol stack.
|
||||
* A typical application will want to call eMBMasterInit() 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 eMBMasterPoll() 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 eMBMasterPoll().
|
||||
*
|
||||
* \code
|
||||
* // Initialize protocol stack in RTU mode for a Master
|
||||
* eMBMasterInit( MB_RTU, 38400, MB_PAR_EVEN );
|
||||
* // Enable the Modbus Protocol Stack.
|
||||
* eMBMasterEnable( );
|
||||
* for( ;; )
|
||||
* {
|
||||
* // Call the main polling loop of the Modbus Master protocol stack.
|
||||
* eMBMasterPoll( );
|
||||
* ...
|
||||
* }
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief Use the default Modbus Master TCP port (502)
|
||||
*/
|
||||
#define MB_MASTER_TCP_PORT_USE_DEFAULT 0
|
||||
|
||||
/* ----------------------- Type definitions ---------------------------------*/
|
||||
/*! \ingroup modbus
|
||||
* \brief Errorcodes used by all function in the Master request.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
MB_MRE_NO_ERR, /*!< no error. */
|
||||
MB_MRE_NO_REG, /*!< illegal register address. */
|
||||
MB_MRE_ILL_ARG, /*!< illegal argument. */
|
||||
MB_MRE_REV_DATA, /*!< receive data error. */
|
||||
MB_MRE_TIMEDOUT, /*!< timeout error occurred. */
|
||||
MB_MRE_MASTER_BUSY, /*!< master is busy now. */
|
||||
MB_MRE_EXE_FUN /*!< execute function error. */
|
||||
} eMBMasterReqErrCode;
|
||||
/*! \ingroup modbus
|
||||
* \brief TimerMode is Master 3 kind of Timer modes.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
MB_TMODE_T35, /*!< Master receive frame T3.5 timeout. */
|
||||
MB_TMODE_RESPOND_TIMEOUT, /*!< Master wait respond for slave. */
|
||||
MB_TMODE_CONVERT_DELAY /*!< Master sent broadcast ,then delay sometime.*/
|
||||
}eMBMasterTimerMode;
|
||||
|
||||
/* ----------------------- Function prototypes ------------------------------*/
|
||||
/*! \ingroup modbus
|
||||
* \brief Initialize the Modbus Master 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 eMBMasterEnable( ) has been called.
|
||||
*
|
||||
* \param eMode If ASCII or RTU mode should be used.
|
||||
* \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 eMBMasterEnable( ). Otherwise one of the following error codes
|
||||
* is returned:
|
||||
* - eMBErrorCode::MB_EPORTERR IF the porting layer returned an error.
|
||||
*/
|
||||
eMBErrorCode eMBMasterInit( eMBMode eMode, UCHAR ucPort,
|
||||
ULONG ulBaudRate, eMBParity eParity );
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief Initialize the Modbus Master 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 eMBMasterTCPInit( USHORT usTCPPort );
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief Release resources used by the protocol stack.
|
||||
*
|
||||
* This function disables the Modbus Master 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 eMBMasterClose( void );
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief Enable the Modbus Master protocol stack.
|
||||
*
|
||||
* This function enables processing of Modbus Master 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 eMBMasterEnable( void );
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief Disable the Modbus Master 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 eMBMasterDisable( void );
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief Check the Modbus Master protocol stack has established or not.
|
||||
*
|
||||
* This function must be called and check the return value before calling
|
||||
* any other functions.
|
||||
*
|
||||
* \return If the protocol stack has been established or not
|
||||
* TRUE. the protocol stack has established
|
||||
* FALSE. the protocol stack hasn't established
|
||||
*/
|
||||
BOOL eMBMasterIsEstablished( void );
|
||||
|
||||
/*! \ingroup modbus
|
||||
* \brief The main pooling loop of the Modbus Master 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 xMBMasterPortEventGet() 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 eMBMasterPoll( void );
|
||||
|
||||
/*! \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 eMBMasterRegisterCB( UCHAR ucFunctionCode,
|
||||
pxMBFunctionHandler pxHandler );
|
||||
|
||||
/* ----------------------- Callback -----------------------------------------*/
|
||||
|
||||
/*! \defgroup modbus_master registers Modbus Registers
|
||||
* \code #include "mb_m.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 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 eMBMasterRegInputCB( 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 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 eMBMasterRegHoldingCB( 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 eMBMasterRegCoilsCB( 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 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 eMBMasterRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress,
|
||||
USHORT usNDiscrete );
|
||||
|
||||
/*! \ingroup modbus
|
||||
*\brief These Modbus functions are called for user when Modbus run in Master Mode.
|
||||
*/
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqReadInputRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs, LONG lTimeOut );
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqWriteHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usRegData, LONG lTimeOut );
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqWriteMultipleHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr,
|
||||
USHORT usNRegs, USHORT * pusDataBuffer, LONG lTimeOut );
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqReadHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs, LONG lTimeOut );
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqReadWriteMultipleHoldingRegister( UCHAR ucSndAddr,
|
||||
USHORT usReadRegAddr, USHORT usNReadRegs, USHORT * pusDataBuffer,
|
||||
USHORT usWriteRegAddr, USHORT usNWriteRegs, LONG lTimeOut );
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqReadCoils( UCHAR ucSndAddr, USHORT usCoilAddr, USHORT usNCoils, LONG lTimeOut );
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqWriteCoil( UCHAR ucSndAddr, USHORT usCoilAddr, USHORT usCoilData, LONG lTimeOut );
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqWriteMultipleCoils( UCHAR ucSndAddr,
|
||||
USHORT usCoilAddr, USHORT usNCoils, UCHAR * pucDataBuffer, LONG lTimeOut );
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqReadDiscreteInputs( UCHAR ucSndAddr, USHORT usDiscreteAddr, USHORT usNDiscreteIn, LONG lTimeOut );
|
||||
|
||||
eMBException
|
||||
eMBMasterFuncReportSlaveID( UCHAR * pucFrame, USHORT * usLen );
|
||||
eMBException
|
||||
eMBMasterFuncReadInputRegister( UCHAR * pucFrame, USHORT * usLen );
|
||||
eMBException
|
||||
eMBMasterFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen );
|
||||
eMBException
|
||||
eMBMasterFuncWriteHoldingRegister( UCHAR * pucFrame, USHORT * usLen );
|
||||
eMBException
|
||||
eMBMasterFuncWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen );
|
||||
eMBException
|
||||
eMBMasterFuncReadCoils( UCHAR * pucFrame, USHORT * usLen );
|
||||
eMBException
|
||||
eMBMasterFuncWriteCoil( UCHAR * pucFrame, USHORT * usLen );
|
||||
eMBException
|
||||
eMBMasterFuncWriteMultipleCoils( UCHAR * pucFrame, USHORT * usLen );
|
||||
eMBException
|
||||
eMBMasterFuncReadDiscreteInputs( UCHAR * pucFrame, USHORT * usLen );
|
||||
eMBException
|
||||
eMBMasterFuncReadWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen );
|
||||
|
||||
/*\ingroup modbus
|
||||
*\brief These functions are interface for Modbus Master
|
||||
*/
|
||||
void vMBMasterGetPDUSndBuf( UCHAR ** pucFrame );
|
||||
UCHAR ucMBMasterGetDestAddress( void );
|
||||
void vMBMasterSetDestAddress( UCHAR Address );
|
||||
BOOL xMBMasterGetCBRunInMasterMode( void );
|
||||
void vMBMasterSetCBRunInMasterMode( BOOL IsMasterMode );
|
||||
USHORT usMBMasterGetPDUSndLength( void );
|
||||
void vMBMasterSetPDUSndLength( USHORT SendPDULength );
|
||||
void vMBMasterSetCurTimerMode( eMBMasterTimerMode eMBTimerMode );
|
||||
BOOL xMBMasterRequestIsBroadcast( void );
|
||||
eMBMasterErrorEventType eMBMasterGetErrorType( void );
|
||||
void vMBMasterSetErrorType( eMBMasterErrorEventType errorType );
|
||||
eMBMasterReqErrCode eMBMasterWaitRequestFinish( void );
|
||||
|
||||
/* ----------------------- Callback -----------------------------------------*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.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 $
|
||||
* $Id: mbconfig.h,v 1.60 2013/08/13 21:19:55 Armink Add Master Functions $
|
||||
*/
|
||||
|
||||
#ifndef _MB_CONFIG_H
|
||||
#define _MB_CONFIG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
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>
|
||||
*/
|
||||
|
||||
#include <rtconfig.h>
|
||||
|
||||
/*! \addtogroup modbus_cfg
|
||||
* @{
|
||||
*/
|
||||
/*! \brief If Modbus Master ASCII support is enabled. */
|
||||
#define MB_MASTER_ASCII_ENABLED ( 0 )
|
||||
/*! \brief If Modbus Master RTU support is enabled. */
|
||||
#define MB_MASTER_RTU_ENABLED ( 1 )
|
||||
/*! \brief If Modbus Master TCP support is enabled. */
|
||||
#define MB_MASTER_TCP_ENABLED ( 0 )
|
||||
|
||||
/*! \brief If Modbus Slave ASCII support is enabled. */
|
||||
#ifdef PKG_MODBUS_SLAVE_ASCII
|
||||
#define MB_SLAVE_ASCII_ENABLED ( 1 )
|
||||
#else
|
||||
#define MB_SLAVE_ASCII_ENABLED ( 0 )
|
||||
#endif
|
||||
|
||||
/*! \brief If Modbus Slave RTU support is enabled. */
|
||||
#ifdef PKG_MODBUS_SLAVE_RTU
|
||||
#define MB_SLAVE_RTU_ENABLED ( 1 )
|
||||
#else
|
||||
#define MB_SLAVE_RTU_ENABLED ( 0 )
|
||||
#endif
|
||||
|
||||
/*! \brief If Modbus Slave TCP support is enabled. */
|
||||
#ifdef PKG_MODBUS_SLAVE_TCP
|
||||
#define MB_SLAVE_TCP_ENABLED ( 1 )
|
||||
#else
|
||||
#define MB_SLAVE_TCP_ENABLED ( 0 )
|
||||
#endif
|
||||
|
||||
/*! \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 ( 1 )
|
||||
/*! \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
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
|
||||
/*! \brief If master send a broadcast frame,the master will wait time of convert to delay,
|
||||
* then master can send other frame */
|
||||
#define MB_MASTER_DELAY_MS_CONVERT (200 )
|
||||
/*! \brief If master send a frame which is not broadcast,the master will wait sometime for slave.
|
||||
* And if slave is not respond in this time,the master will process this timeout error.
|
||||
* Then master can send other frame */
|
||||
#define MB_MASTER_TIMEOUT_MS_RESPOND (100 )
|
||||
/*! \brief The total slaves in Modbus Master system. Default 16.
|
||||
* \note : The slave ID must be continuous from 1.*/
|
||||
#define MB_MASTER_TOTAL_SLAVE_NUM ( 16 )
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.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
|
||||
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
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.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
|
||||
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
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,207 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.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 $
|
||||
* mbport.h,v 1.60 2013/08/17 11:42:56 Armink Add Master Functions $
|
||||
*/
|
||||
|
||||
#ifndef _MB_PORT_H
|
||||
#define _MB_PORT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
|
||||
/* ----------------------- Type definitions ---------------------------------*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
EV_READY = 1<<0, /*!< Startup finished. */
|
||||
EV_FRAME_RECEIVED = 1<<1, /*!< Frame received. */
|
||||
EV_EXECUTE = 1<<2, /*!< Execute function. */
|
||||
EV_FRAME_SENT = 1<<3 /*!< Frame sent. */
|
||||
} eMBEventType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
EV_MASTER_READY = 1<<0, /*!< Startup finished. */
|
||||
EV_MASTER_FRAME_RECEIVED = 1<<1, /*!< Frame received. */
|
||||
EV_MASTER_EXECUTE = 1<<2, /*!< Execute function. */
|
||||
EV_MASTER_FRAME_SENT = 1<<3, /*!< Frame sent. */
|
||||
EV_MASTER_ERROR_PROCESS = 1<<4, /*!< Frame error process. */
|
||||
EV_MASTER_PROCESS_SUCESS = 1<<5, /*!< Request process success. */
|
||||
EV_MASTER_ERROR_RESPOND_TIMEOUT = 1<<6, /*!< Request respond timeout. */
|
||||
EV_MASTER_ERROR_RECEIVE_DATA = 1<<7, /*!< Request receive data error. */
|
||||
EV_MASTER_ERROR_EXECUTE_FUNCTION = 1<<8, /*!< Request execute function error. */
|
||||
} eMBMasterEventType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
EV_ERROR_RESPOND_TIMEOUT, /*!< Slave respond timeout. */
|
||||
EV_ERROR_RECEIVE_DATA, /*!< Receive frame data erroe. */
|
||||
EV_ERROR_EXECUTE_FUNCTION, /*!< Execute function error. */
|
||||
} eMBMasterErrorEventType;
|
||||
|
||||
/*! \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 );
|
||||
|
||||
BOOL xMBMasterPortEventInit( void );
|
||||
|
||||
BOOL xMBMasterPortEventPost( eMBMasterEventType eEvent );
|
||||
|
||||
BOOL xMBMasterPortEventGet( /*@out@ */ eMBMasterEventType * eEvent );
|
||||
|
||||
void vMBMasterOsResInit( void );
|
||||
|
||||
BOOL xMBMasterRunResTake( int32_t time );
|
||||
|
||||
void vMBMasterRunResRelease( void );
|
||||
|
||||
/* ----------------------- 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 );
|
||||
|
||||
BOOL xMBMasterPortSerialInit( UCHAR ucPort, ULONG ulBaudRate,
|
||||
UCHAR ucDataBits, eMBParity eParity );
|
||||
|
||||
void vMBMasterPortClose( void );
|
||||
|
||||
void xMBMasterPortSerialClose( void );
|
||||
|
||||
void vMBMasterPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable );
|
||||
|
||||
INLINE BOOL xMBMasterPortSerialGetByte( CHAR * pucByte );
|
||||
|
||||
INLINE BOOL xMBMasterPortSerialPutByte( CHAR ucByte );
|
||||
|
||||
/* ----------------------- Timers functions ---------------------------------*/
|
||||
BOOL xMBPortTimersInit( USHORT usTimeOut50us );
|
||||
|
||||
void xMBPortTimersClose( void );
|
||||
|
||||
INLINE void vMBPortTimersEnable( void );
|
||||
|
||||
INLINE void vMBPortTimersDisable( void );
|
||||
|
||||
BOOL xMBMasterPortTimersInit( USHORT usTimeOut50us );
|
||||
|
||||
void xMBMasterPortTimersClose( void );
|
||||
|
||||
INLINE void vMBMasterPortTimersT35Enable( void );
|
||||
|
||||
INLINE void vMBMasterPortTimersConvertDelayEnable( void );
|
||||
|
||||
INLINE void vMBMasterPortTimersRespondTimeoutEnable( void );
|
||||
|
||||
INLINE void vMBMasterPortTimersDisable( void );
|
||||
|
||||
/* ----------------- Callback for the master error process ------------------*/
|
||||
void vMBMasterErrorCBRespondTimeout( UCHAR ucDestAddress, const UCHAR* pucPDUData,
|
||||
USHORT ucPDULength );
|
||||
|
||||
void vMBMasterErrorCBReceiveData( UCHAR ucDestAddress, const UCHAR* pucPDUData,
|
||||
USHORT ucPDULength );
|
||||
|
||||
void vMBMasterErrorCBExecuteFunction( UCHAR ucDestAddress, const UCHAR* pucPDUData,
|
||||
USHORT ucPDULength );
|
||||
|
||||
void vMBMasterCBRequestScuuess( 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 );
|
||||
|
||||
extern BOOL( *pxMBMasterFrameCBByteReceived ) ( void );
|
||||
|
||||
extern BOOL( *pxMBMasterFrameCBTransmitterEmpty ) ( void );
|
||||
|
||||
extern BOOL( *pxMBMasterPortCBTimerExpired ) ( 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
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.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
|
||||
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
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,412 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.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_SLAVE_RTU_ENABLED == 1
|
||||
#include "mbrtu.h"
|
||||
#endif
|
||||
#if MB_SLAVE_ASCII_ENABLED == 1
|
||||
#include "mbascii.h"
|
||||
#endif
|
||||
#if MB_SLAVE_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.
|
||||
* Using for Modbus Slave
|
||||
*/
|
||||
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.
|
||||
* Using for Modbus Slave
|
||||
*/
|
||||
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_SLAVE_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_SLAVE_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;
|
||||
break;
|
||||
}
|
||||
|
||||
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_SLAVE_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;
|
||||
}
|
||||
@@ -1,429 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
|
||||
* 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_m.c,v 1.60 2013/08/20 11:18:10 Armink Add Master Functions $
|
||||
*/
|
||||
|
||||
/* ----------------------- System includes ----------------------------------*/
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
|
||||
/* ----------------------- Platform includes --------------------------------*/
|
||||
#include "port.h"
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
|
||||
#include "mb.h"
|
||||
#include "mb_m.h"
|
||||
#include "mbconfig.h"
|
||||
#include "mbframe.h"
|
||||
#include "mbproto.h"
|
||||
#include "mbfunc.h"
|
||||
|
||||
#include "mbport.h"
|
||||
#if MB_MASTER_RTU_ENABLED == 1
|
||||
#include "mbrtu.h"
|
||||
#endif
|
||||
#if MB_MASTER_ASCII_ENABLED == 1
|
||||
#include "mbascii.h"
|
||||
#endif
|
||||
#if MB_MASTER_TCP_ENABLED == 1
|
||||
#include "mbtcp.h"
|
||||
#endif
|
||||
|
||||
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
|
||||
|
||||
#ifndef MB_PORT_HAS_CLOSE
|
||||
#define MB_PORT_HAS_CLOSE 0
|
||||
#endif
|
||||
|
||||
/* ----------------------- Static variables ---------------------------------*/
|
||||
|
||||
static UCHAR ucMBMasterDestAddress;
|
||||
static BOOL xMBRunInMasterMode = FALSE;
|
||||
static eMBMasterErrorEventType eMBMasterCurErrorType;
|
||||
|
||||
static enum
|
||||
{
|
||||
STATE_ENABLED,
|
||||
STATE_DISABLED,
|
||||
STATE_NOT_INITIALIZED,
|
||||
STATE_ESTABLISHED,
|
||||
} 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.
|
||||
* Using for Modbus Master,Add by Armink 20130813
|
||||
*/
|
||||
static peMBFrameSend peMBMasterFrameSendCur;
|
||||
static pvMBFrameStart pvMBMasterFrameStartCur;
|
||||
static pvMBFrameStop pvMBMasterFrameStopCur;
|
||||
static peMBFrameReceive peMBMasterFrameReceiveCur;
|
||||
static pvMBFrameClose pvMBMasterFrameCloseCur;
|
||||
|
||||
/* 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.
|
||||
* Using for Modbus Master,Add by Armink 20130813
|
||||
*/
|
||||
BOOL( *pxMBMasterFrameCBByteReceived ) ( void );
|
||||
BOOL( *pxMBMasterFrameCBTransmitterEmpty ) ( void );
|
||||
BOOL( *pxMBMasterPortCBTimerExpired ) ( void );
|
||||
|
||||
BOOL( *pxMBMasterFrameCBReceiveFSMCur ) ( void );
|
||||
BOOL( *pxMBMasterFrameCBTransmitFSMCur ) ( void );
|
||||
|
||||
/* An array of Modbus functions handlers which associates Modbus function
|
||||
* codes with implementing functions.
|
||||
*/
|
||||
static xMBFunctionHandler xMasterFuncHandlers[MB_FUNC_HANDLERS_MAX] = {
|
||||
#if MB_FUNC_OTHER_REP_SLAVEID_ENABLED > 0
|
||||
//TODO Add Master function define
|
||||
{MB_FUNC_OTHER_REPORT_SLAVEID, eMBFuncReportSlaveID},
|
||||
#endif
|
||||
#if MB_FUNC_READ_INPUT_ENABLED > 0
|
||||
{MB_FUNC_READ_INPUT_REGISTER, eMBMasterFuncReadInputRegister},
|
||||
#endif
|
||||
#if MB_FUNC_READ_HOLDING_ENABLED > 0
|
||||
{MB_FUNC_READ_HOLDING_REGISTER, eMBMasterFuncReadHoldingRegister},
|
||||
#endif
|
||||
#if MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED > 0
|
||||
{MB_FUNC_WRITE_MULTIPLE_REGISTERS, eMBMasterFuncWriteMultipleHoldingRegister},
|
||||
#endif
|
||||
#if MB_FUNC_WRITE_HOLDING_ENABLED > 0
|
||||
{MB_FUNC_WRITE_REGISTER, eMBMasterFuncWriteHoldingRegister},
|
||||
#endif
|
||||
#if MB_FUNC_READWRITE_HOLDING_ENABLED > 0
|
||||
{MB_FUNC_READWRITE_MULTIPLE_REGISTERS, eMBMasterFuncReadWriteMultipleHoldingRegister},
|
||||
#endif
|
||||
#if MB_FUNC_READ_COILS_ENABLED > 0
|
||||
{MB_FUNC_READ_COILS, eMBMasterFuncReadCoils},
|
||||
#endif
|
||||
#if MB_FUNC_WRITE_COIL_ENABLED > 0
|
||||
{MB_FUNC_WRITE_SINGLE_COIL, eMBMasterFuncWriteCoil},
|
||||
#endif
|
||||
#if MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED > 0
|
||||
{MB_FUNC_WRITE_MULTIPLE_COILS, eMBMasterFuncWriteMultipleCoils},
|
||||
#endif
|
||||
#if MB_FUNC_READ_DISCRETE_INPUTS_ENABLED > 0
|
||||
{MB_FUNC_READ_DISCRETE_INPUTS, eMBMasterFuncReadDiscreteInputs},
|
||||
#endif
|
||||
};
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
eMBErrorCode
|
||||
eMBMasterInit( eMBMode eMode, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
|
||||
switch (eMode)
|
||||
{
|
||||
#if MB_MASTER_RTU_ENABLED > 0
|
||||
case MB_RTU:
|
||||
pvMBMasterFrameStartCur = eMBMasterRTUStart;
|
||||
pvMBMasterFrameStopCur = eMBMasterRTUStop;
|
||||
peMBMasterFrameSendCur = eMBMasterRTUSend;
|
||||
peMBMasterFrameReceiveCur = eMBMasterRTUReceive;
|
||||
pvMBMasterFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBMasterPortClose : NULL;
|
||||
pxMBMasterFrameCBByteReceived = xMBMasterRTUReceiveFSM;
|
||||
pxMBMasterFrameCBTransmitterEmpty = xMBMasterRTUTransmitFSM;
|
||||
pxMBMasterPortCBTimerExpired = xMBMasterRTUTimerExpired;
|
||||
|
||||
eStatus = eMBMasterRTUInit(ucPort, ulBaudRate, eParity);
|
||||
break;
|
||||
#endif
|
||||
#if MB_MASTER_ASCII_ENABLED > 0
|
||||
case MB_ASCII:
|
||||
pvMBMasterFrameStartCur = eMBMasterASCIIStart;
|
||||
pvMBMasterFrameStopCur = eMBMasterASCIIStop;
|
||||
peMBMasterFrameSendCur = eMBMasterASCIISend;
|
||||
peMBMasterFrameReceiveCur = eMBMasterASCIIReceive;
|
||||
pvMBMasterFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBMasterPortClose : NULL;
|
||||
pxMBMasterFrameCBByteReceived = xMBMasterASCIIReceiveFSM;
|
||||
pxMBMasterFrameCBTransmitterEmpty = xMBMasterASCIITransmitFSM;
|
||||
pxMBMasterPortCBTimerExpired = xMBMasterASCIITimerT1SExpired;
|
||||
|
||||
eStatus = eMBMasterASCIIInit(ucPort, ulBaudRate, eParity );
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
eStatus = MB_EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (eStatus == MB_ENOERR)
|
||||
{
|
||||
if (!xMBMasterPortEventInit())
|
||||
{
|
||||
/* port dependent event module initalization failed. */
|
||||
eStatus = MB_EPORTERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
eMBState = STATE_DISABLED;
|
||||
}
|
||||
/* initialize the OS resource for modbus master. */
|
||||
vMBMasterOsResInit();
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
eMBErrorCode
|
||||
eMBMasterClose( void )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
|
||||
if( eMBState == STATE_DISABLED )
|
||||
{
|
||||
if( pvMBMasterFrameCloseCur != NULL )
|
||||
{
|
||||
pvMBMasterFrameCloseCur( );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EILLSTATE;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
eMBErrorCode
|
||||
eMBMasterEnable( void )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
|
||||
if( eMBState == STATE_DISABLED )
|
||||
{
|
||||
/* Activate the protocol stack. */
|
||||
pvMBMasterFrameStartCur( );
|
||||
eMBState = STATE_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EILLSTATE;
|
||||
}
|
||||
|
||||
xMBMasterPortEventPost( EV_MASTER_FRAME_RECEIVED );
|
||||
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
eMBErrorCode
|
||||
eMBMasterDisable( void )
|
||||
{
|
||||
eMBErrorCode eStatus;
|
||||
|
||||
if(( eMBState == STATE_ENABLED ) || ( eMBState == STATE_ESTABLISHED))
|
||||
{
|
||||
pvMBMasterFrameStopCur( );
|
||||
eMBState = STATE_DISABLED;
|
||||
eStatus = MB_ENOERR;
|
||||
}
|
||||
else if( eMBState == STATE_DISABLED )
|
||||
{
|
||||
eStatus = MB_ENOERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EILLSTATE;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
BOOL
|
||||
eMBMasterIsEstablished( void )
|
||||
{
|
||||
if(eMBState == STATE_ESTABLISHED)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
eMBErrorCode
|
||||
eMBMasterPoll( void )
|
||||
{
|
||||
static UCHAR *ucMBFrame;
|
||||
static UCHAR ucRcvAddress;
|
||||
static UCHAR ucFunctionCode;
|
||||
static USHORT usLength;
|
||||
static eMBException eException;
|
||||
|
||||
int i , j;
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
eMBMasterEventType eEvent;
|
||||
eMBMasterErrorEventType errorType;
|
||||
|
||||
/* Check if the protocol stack is ready. */
|
||||
if(( eMBState != STATE_ENABLED ) && ( eMBState != STATE_ESTABLISHED))
|
||||
{
|
||||
return MB_EILLSTATE;
|
||||
}
|
||||
|
||||
/* Check if there is a event available. If not return control to caller.
|
||||
* Otherwise we will handle the event. */
|
||||
if( xMBMasterPortEventGet( &eEvent ) == TRUE )
|
||||
{
|
||||
switch ( eEvent )
|
||||
{
|
||||
case EV_MASTER_READY:
|
||||
eMBState = STATE_ESTABLISHED;
|
||||
break;
|
||||
|
||||
case EV_MASTER_FRAME_RECEIVED:
|
||||
eStatus = peMBMasterFrameReceiveCur( &ucRcvAddress, &ucMBFrame, &usLength );
|
||||
/* Check if the frame is for us. If not ,send an error process event. */
|
||||
if ( ( eStatus == MB_ENOERR ) && ( ucRcvAddress == ucMBMasterGetDestAddress() ) )
|
||||
{
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_EXECUTE );
|
||||
}
|
||||
else
|
||||
{
|
||||
vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA);
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_MASTER_EXECUTE:
|
||||
ucFunctionCode = ucMBFrame[MB_PDU_FUNC_OFF];
|
||||
eException = MB_EX_ILLEGAL_FUNCTION;
|
||||
/* If receive frame has exception .The receive function code highest bit is 1.*/
|
||||
if(ucFunctionCode >> 7) {
|
||||
eException = (eMBException)ucMBFrame[MB_PDU_DATA_OFF];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < MB_FUNC_HANDLERS_MAX; i++)
|
||||
{
|
||||
/* No more function handlers registered. Abort. */
|
||||
if (xMasterFuncHandlers[i].ucFunctionCode == 0) {
|
||||
break;
|
||||
}
|
||||
else if (xMasterFuncHandlers[i].ucFunctionCode == ucFunctionCode) {
|
||||
vMBMasterSetCBRunInMasterMode(TRUE);
|
||||
/* If master request is broadcast,
|
||||
* the master need execute function for all slave.
|
||||
*/
|
||||
if ( xMBMasterRequestIsBroadcast() ) {
|
||||
usLength = usMBMasterGetPDUSndLength();
|
||||
for(j = 1; j <= MB_MASTER_TOTAL_SLAVE_NUM; j++){
|
||||
vMBMasterSetDestAddress(j);
|
||||
eException = xMasterFuncHandlers[i].pxHandler(ucMBFrame, &usLength);
|
||||
}
|
||||
}
|
||||
else {
|
||||
eException = xMasterFuncHandlers[i].pxHandler(ucMBFrame, &usLength);
|
||||
}
|
||||
vMBMasterSetCBRunInMasterMode(FALSE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* If master has exception ,Master will send error process.Otherwise the Master is idle.*/
|
||||
if (eException != MB_EX_NONE) {
|
||||
vMBMasterSetErrorType(EV_ERROR_EXECUTE_FUNCTION);
|
||||
( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
|
||||
}
|
||||
else {
|
||||
vMBMasterCBRequestScuuess( );
|
||||
vMBMasterRunResRelease( );
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_MASTER_FRAME_SENT:
|
||||
/* Master is busy now. */
|
||||
vMBMasterGetPDUSndBuf( &ucMBFrame );
|
||||
eStatus = peMBMasterFrameSendCur( ucMBMasterGetDestAddress(), ucMBFrame, usMBMasterGetPDUSndLength() );
|
||||
break;
|
||||
|
||||
case EV_MASTER_ERROR_PROCESS:
|
||||
/* Execute specified error process callback function. */
|
||||
errorType = eMBMasterGetErrorType();
|
||||
vMBMasterGetPDUSndBuf( &ucMBFrame );
|
||||
switch (errorType) {
|
||||
case EV_ERROR_RESPOND_TIMEOUT:
|
||||
vMBMasterErrorCBRespondTimeout(ucMBMasterGetDestAddress(),
|
||||
ucMBFrame, usMBMasterGetPDUSndLength());
|
||||
break;
|
||||
case EV_ERROR_RECEIVE_DATA:
|
||||
vMBMasterErrorCBReceiveData(ucMBMasterGetDestAddress(),
|
||||
ucMBFrame, usMBMasterGetPDUSndLength());
|
||||
break;
|
||||
case EV_ERROR_EXECUTE_FUNCTION:
|
||||
vMBMasterErrorCBExecuteFunction(ucMBMasterGetDestAddress(),
|
||||
ucMBFrame, usMBMasterGetPDUSndLength());
|
||||
break;
|
||||
}
|
||||
vMBMasterRunResRelease();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return MB_ENOERR;
|
||||
}
|
||||
|
||||
/* Get whether the Modbus Master is run in master mode.*/
|
||||
BOOL xMBMasterGetCBRunInMasterMode( void )
|
||||
{
|
||||
return xMBRunInMasterMode;
|
||||
}
|
||||
/* Set whether the Modbus Master is run in master mode.*/
|
||||
void vMBMasterSetCBRunInMasterMode( BOOL IsMasterMode )
|
||||
{
|
||||
xMBRunInMasterMode = IsMasterMode;
|
||||
}
|
||||
/* Get Modbus Master send destination address. */
|
||||
UCHAR ucMBMasterGetDestAddress( void )
|
||||
{
|
||||
return ucMBMasterDestAddress;
|
||||
}
|
||||
/* Set Modbus Master send destination address. */
|
||||
void vMBMasterSetDestAddress( UCHAR Address )
|
||||
{
|
||||
ucMBMasterDestAddress = Address;
|
||||
}
|
||||
/* Get Modbus Master current error event type. */
|
||||
eMBMasterErrorEventType eMBMasterGetErrorType( void )
|
||||
{
|
||||
return eMBMasterCurErrorType;
|
||||
}
|
||||
/* Set Modbus Master current error event type. */
|
||||
void vMBMasterSetErrorType( eMBMasterErrorEventType errorType )
|
||||
{
|
||||
eMBMasterCurErrorType = errorType;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.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
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.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 $
|
||||
* File: $Id: mbrtu.h,v 1.60 2013/08/17 13:11:42 Armink Add Master Functions $
|
||||
*/
|
||||
#include "mbconfig.h"
|
||||
|
||||
#ifndef _MB_RTU_H
|
||||
#define _MB_RTU_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
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 );
|
||||
|
||||
#if MB_MASTER_RTU_ENABLED > 0
|
||||
eMBErrorCode eMBMasterRTUInit( UCHAR ucPort, ULONG ulBaudRate,eMBParity eParity );
|
||||
void eMBMasterRTUStart( void );
|
||||
void eMBMasterRTUStop( void );
|
||||
eMBErrorCode eMBMasterRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength );
|
||||
eMBErrorCode eMBMasterRTUSend( UCHAR slaveAddress, const UCHAR * pucFrame, USHORT usLength );
|
||||
BOOL xMBMasterRTUReceiveFSM( void );
|
||||
BOOL xMBMasterRTUTransmitFSM( void );
|
||||
BOOL xMBMasterRTUTimerExpired( void );
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,446 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2013 China Beijing Armink <armink.ztl@gmail.com>
|
||||
* 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_m.c,v 1.60 2013/08/17 11:42:56 Armink Add Master Functions $
|
||||
*/
|
||||
|
||||
/* ----------------------- System includes ----------------------------------*/
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
|
||||
/* ----------------------- Platform includes --------------------------------*/
|
||||
#include "port.h"
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mb_m.h"
|
||||
#include "mbrtu.h"
|
||||
#include "mbframe.h"
|
||||
|
||||
#include "mbcrc.h"
|
||||
#include "mbport.h"
|
||||
|
||||
#if MB_MASTER_RTU_ENABLED > 0
|
||||
/* ----------------------- 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_M_RX_INIT, /*!< Receiver is in initial state. */
|
||||
STATE_M_RX_IDLE, /*!< Receiver is in idle state. */
|
||||
STATE_M_RX_RCV, /*!< Frame is beeing received. */
|
||||
STATE_M_RX_ERROR, /*!< If the frame is invalid. */
|
||||
} eMBMasterRcvState;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
STATE_M_TX_IDLE, /*!< Transmitter is in idle state. */
|
||||
STATE_M_TX_XMIT, /*!< Transmitter is in transfer state. */
|
||||
STATE_M_TX_XFWR, /*!< Transmitter is in transfer finish and wait receive state. */
|
||||
} eMBMasterSndState;
|
||||
|
||||
/* ----------------------- Static variables ---------------------------------*/
|
||||
static volatile eMBMasterSndState eSndState;
|
||||
static volatile eMBMasterRcvState eRcvState;
|
||||
|
||||
static volatile UCHAR ucMasterRTUSndBuf[MB_PDU_SIZE_MAX];
|
||||
static volatile UCHAR ucMasterRTURcvBuf[MB_SER_PDU_SIZE_MAX];
|
||||
static volatile USHORT usMasterSendPDULength;
|
||||
|
||||
static volatile UCHAR *pucMasterSndBufferCur;
|
||||
static volatile USHORT usMasterSndBufferCount;
|
||||
|
||||
static volatile USHORT usMasterRcvBufferPos;
|
||||
static volatile BOOL xFrameIsBroadcast = FALSE;
|
||||
|
||||
static volatile eMBMasterTimerMode eMasterCurTimerMode;
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
eMBErrorCode
|
||||
eMBMasterRTUInit(UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
ULONG usTimerT35_50us;
|
||||
|
||||
ENTER_CRITICAL_SECTION( );
|
||||
|
||||
/* Modbus RTU uses 8 Databits. */
|
||||
if( xMBMasterPortSerialInit( 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( xMBMasterPortTimersInit( ( USHORT ) usTimerT35_50us ) != TRUE )
|
||||
{
|
||||
eStatus = MB_EPORTERR;
|
||||
}
|
||||
}
|
||||
EXIT_CRITICAL_SECTION( );
|
||||
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
void
|
||||
eMBMasterRTUStart( void )
|
||||
{
|
||||
ENTER_CRITICAL_SECTION( );
|
||||
/* Initially the receiver is in the state STATE_M_RX_INIT. we start
|
||||
* the timer and if no character is received within t3.5 we change
|
||||
* to STATE_M_RX_IDLE. This makes sure that we delay startup of the
|
||||
* modbus protocol stack until the bus is free.
|
||||
*/
|
||||
eRcvState = STATE_M_RX_INIT;
|
||||
vMBMasterPortSerialEnable( TRUE, FALSE );
|
||||
vMBMasterPortTimersT35Enable( );
|
||||
|
||||
EXIT_CRITICAL_SECTION( );
|
||||
}
|
||||
|
||||
void
|
||||
eMBMasterRTUStop( void )
|
||||
{
|
||||
ENTER_CRITICAL_SECTION( );
|
||||
vMBMasterPortSerialEnable( FALSE, FALSE );
|
||||
vMBMasterPortTimersDisable( );
|
||||
EXIT_CRITICAL_SECTION( );
|
||||
}
|
||||
|
||||
eMBErrorCode
|
||||
eMBMasterRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
|
||||
ENTER_CRITICAL_SECTION( );
|
||||
RT_ASSERT( usMasterRcvBufferPos < MB_SER_PDU_SIZE_MAX );
|
||||
|
||||
/* Length and CRC check */
|
||||
if( ( usMasterRcvBufferPos >= MB_SER_PDU_SIZE_MIN )
|
||||
&& ( usMBCRC16( ( UCHAR * ) ucMasterRTURcvBuf, usMasterRcvBufferPos ) == 0 ) )
|
||||
{
|
||||
/* Save the address field. All frames are passed to the upper layed
|
||||
* and the decision if a frame is used is done there.
|
||||
*/
|
||||
*pucRcvAddress = ucMasterRTURcvBuf[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 )( usMasterRcvBufferPos - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_CRC );
|
||||
|
||||
/* Return the start of the Modbus PDU to the caller. */
|
||||
*pucFrame = ( UCHAR * ) & ucMasterRTURcvBuf[MB_SER_PDU_PDU_OFF];
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EIO;
|
||||
}
|
||||
|
||||
EXIT_CRITICAL_SECTION( );
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
eMBErrorCode
|
||||
eMBMasterRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
USHORT usCRC16;
|
||||
|
||||
if ( ucSlaveAddress > MB_MASTER_TOTAL_SLAVE_NUM ) return MB_EINVAL;
|
||||
|
||||
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_M_RX_IDLE )
|
||||
{
|
||||
/* First byte before the Modbus-PDU is the slave address. */
|
||||
pucMasterSndBufferCur = ( UCHAR * ) pucFrame - 1;
|
||||
usMasterSndBufferCount = 1;
|
||||
|
||||
/* Now copy the Modbus-PDU into the Modbus-Serial-Line-PDU. */
|
||||
pucMasterSndBufferCur[MB_SER_PDU_ADDR_OFF] = ucSlaveAddress;
|
||||
usMasterSndBufferCount += usLength;
|
||||
|
||||
/* Calculate CRC16 checksum for Modbus-Serial-Line-PDU. */
|
||||
usCRC16 = usMBCRC16( ( UCHAR * ) pucMasterSndBufferCur, usMasterSndBufferCount );
|
||||
ucMasterRTUSndBuf[usMasterSndBufferCount++] = ( UCHAR )( usCRC16 & 0xFF );
|
||||
ucMasterRTUSndBuf[usMasterSndBufferCount++] = ( UCHAR )( usCRC16 >> 8 );
|
||||
|
||||
/* Activate the transmitter. */
|
||||
eSndState = STATE_M_TX_XMIT;
|
||||
vMBMasterPortSerialEnable( FALSE, TRUE );
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EIO;
|
||||
}
|
||||
EXIT_CRITICAL_SECTION( );
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBMasterRTUReceiveFSM( void )
|
||||
{
|
||||
BOOL xTaskNeedSwitch = FALSE;
|
||||
UCHAR ucByte;
|
||||
|
||||
RT_ASSERT(( eSndState == STATE_M_TX_IDLE ) || ( eSndState == STATE_M_TX_XFWR ));
|
||||
|
||||
/* Always read the character. */
|
||||
( void )xMBMasterPortSerialGetByte( ( 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_M_RX_INIT:
|
||||
vMBMasterPortTimersT35Enable( );
|
||||
break;
|
||||
|
||||
/* In the error state we wait until all characters in the
|
||||
* damaged frame are transmitted.
|
||||
*/
|
||||
case STATE_M_RX_ERROR:
|
||||
vMBMasterPortTimersT35Enable( );
|
||||
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_RECEIVCE and disable early
|
||||
* the timer of respond timeout .
|
||||
*/
|
||||
case STATE_M_RX_IDLE:
|
||||
/* In time of respond timeout,the receiver receive a frame.
|
||||
* Disable timer of respond timeout and change the transmiter state to idle.
|
||||
*/
|
||||
vMBMasterPortTimersDisable( );
|
||||
eSndState = STATE_M_TX_IDLE;
|
||||
|
||||
usMasterRcvBufferPos = 0;
|
||||
ucMasterRTURcvBuf[usMasterRcvBufferPos++] = ucByte;
|
||||
eRcvState = STATE_M_RX_RCV;
|
||||
|
||||
/* Enable t3.5 timers. */
|
||||
vMBMasterPortTimersT35Enable( );
|
||||
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_M_RX_RCV:
|
||||
if( usMasterRcvBufferPos < MB_SER_PDU_SIZE_MAX )
|
||||
{
|
||||
ucMasterRTURcvBuf[usMasterRcvBufferPos++] = ucByte;
|
||||
}
|
||||
else
|
||||
{
|
||||
eRcvState = STATE_M_RX_ERROR;
|
||||
}
|
||||
vMBMasterPortTimersT35Enable();
|
||||
break;
|
||||
}
|
||||
return xTaskNeedSwitch;
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBMasterRTUTransmitFSM( void )
|
||||
{
|
||||
BOOL xNeedPoll = FALSE;
|
||||
|
||||
RT_ASSERT( eRcvState == STATE_M_RX_IDLE );
|
||||
|
||||
switch ( eSndState )
|
||||
{
|
||||
/* We should not get a transmitter event if the transmitter is in
|
||||
* idle state. */
|
||||
case STATE_M_TX_IDLE:
|
||||
/* enable receiver/disable transmitter. */
|
||||
vMBMasterPortSerialEnable( TRUE, FALSE );
|
||||
break;
|
||||
|
||||
case STATE_M_TX_XMIT:
|
||||
/* check if we are finished. */
|
||||
if( usMasterSndBufferCount != 0 )
|
||||
{
|
||||
xMBMasterPortSerialPutByte( ( CHAR )*pucMasterSndBufferCur );
|
||||
pucMasterSndBufferCur++; /* next byte in sendbuffer. */
|
||||
usMasterSndBufferCount--;
|
||||
}
|
||||
else
|
||||
{
|
||||
xFrameIsBroadcast = ( ucMasterRTUSndBuf[MB_SER_PDU_ADDR_OFF] == MB_ADDRESS_BROADCAST ) ? TRUE : FALSE;
|
||||
/* Disable transmitter. This prevents another transmit buffer
|
||||
* empty interrupt. */
|
||||
eSndState = STATE_M_TX_XFWR;
|
||||
vMBMasterPortSerialEnable( TRUE, FALSE );
|
||||
/* If the frame is broadcast ,master will enable timer of convert delay,
|
||||
* else master will enable timer of respond timeout. */
|
||||
if ( xFrameIsBroadcast == TRUE )
|
||||
{
|
||||
vMBMasterPortTimersConvertDelayEnable( );
|
||||
}
|
||||
else
|
||||
{
|
||||
vMBMasterPortTimersRespondTimeoutEnable( );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return xNeedPoll;
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBMasterRTUTimerExpired(void)
|
||||
{
|
||||
BOOL xNeedPoll = FALSE;
|
||||
|
||||
switch (eRcvState)
|
||||
{
|
||||
/* Timer t35 expired. Startup phase is finished. */
|
||||
case STATE_M_RX_INIT:
|
||||
xNeedPoll = xMBMasterPortEventPost(EV_MASTER_READY);
|
||||
break;
|
||||
|
||||
/* A frame was received and t35 expired. Notify the listener that
|
||||
* a new frame was received. */
|
||||
case STATE_M_RX_RCV:
|
||||
xNeedPoll = xMBMasterPortEventPost(EV_MASTER_FRAME_RECEIVED);
|
||||
break;
|
||||
|
||||
/* An error occured while receiving the frame. */
|
||||
case STATE_M_RX_ERROR:
|
||||
vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA);
|
||||
xNeedPoll = xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
|
||||
break;
|
||||
|
||||
/* Function called in an illegal state. */
|
||||
default:
|
||||
RT_ASSERT(
|
||||
( eRcvState == STATE_M_RX_INIT ) || ( eRcvState == STATE_M_RX_RCV ) ||
|
||||
( eRcvState == STATE_M_RX_ERROR ) || ( eRcvState == STATE_M_RX_IDLE ));
|
||||
break;
|
||||
}
|
||||
eRcvState = STATE_M_RX_IDLE;
|
||||
|
||||
switch (eSndState)
|
||||
{
|
||||
/* A frame was send finish and convert delay or respond timeout expired.
|
||||
* If the frame is broadcast,The master will idle,and if the frame is not
|
||||
* broadcast.Notify the listener process error.*/
|
||||
case STATE_M_TX_XFWR:
|
||||
if ( xFrameIsBroadcast == FALSE ) {
|
||||
vMBMasterSetErrorType(EV_ERROR_RESPOND_TIMEOUT);
|
||||
xNeedPoll = xMBMasterPortEventPost(EV_MASTER_ERROR_PROCESS);
|
||||
}
|
||||
break;
|
||||
/* Function called in an illegal state. */
|
||||
default:
|
||||
RT_ASSERT(
|
||||
( eSndState == STATE_M_TX_XFWR ) || ( eSndState == STATE_M_TX_IDLE ));
|
||||
break;
|
||||
}
|
||||
eSndState = STATE_M_TX_IDLE;
|
||||
|
||||
vMBMasterPortTimersDisable( );
|
||||
/* If timer mode is convert delay, the master event then turns EV_MASTER_EXECUTE status. */
|
||||
if (eMasterCurTimerMode == MB_TMODE_CONVERT_DELAY) {
|
||||
xNeedPoll = xMBMasterPortEventPost( EV_MASTER_EXECUTE );
|
||||
}
|
||||
|
||||
return xNeedPoll;
|
||||
}
|
||||
|
||||
/* Get Modbus Master send RTU's buffer address pointer.*/
|
||||
void vMBMasterGetRTUSndBuf( UCHAR ** pucFrame )
|
||||
{
|
||||
*pucFrame = ( UCHAR * ) ucMasterRTUSndBuf;
|
||||
}
|
||||
|
||||
/* Get Modbus Master send PDU's buffer address pointer.*/
|
||||
void vMBMasterGetPDUSndBuf( UCHAR ** pucFrame )
|
||||
{
|
||||
*pucFrame = ( UCHAR * ) &ucMasterRTUSndBuf[MB_SER_PDU_PDU_OFF];
|
||||
}
|
||||
|
||||
/* Set Modbus Master send PDU's buffer length.*/
|
||||
void vMBMasterSetPDUSndLength( USHORT SendPDULength )
|
||||
{
|
||||
usMasterSendPDULength = SendPDULength;
|
||||
}
|
||||
|
||||
/* Get Modbus Master send PDU's buffer length.*/
|
||||
USHORT usMBMasterGetPDUSndLength( void )
|
||||
{
|
||||
return usMasterSendPDULength;
|
||||
}
|
||||
|
||||
/* Set Modbus Master current timer mode.*/
|
||||
void vMBMasterSetCurTimerMode( eMBMasterTimerMode eMBTimerMode )
|
||||
{
|
||||
eMasterCurTimerMode = eMBTimerMode;
|
||||
}
|
||||
|
||||
/* The master request is broadcast? */
|
||||
BOOL xMBMasterRequestIsBroadcast( void ){
|
||||
return xFrameIsBroadcast;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.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: mbtcp.c,v 1.3 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 "mbconfig.h"
|
||||
#include "mbtcp.h"
|
||||
#include "mbframe.h"
|
||||
#include "mbport.h"
|
||||
|
||||
#if MB_SLAVE_TCP_ENABLED > 0
|
||||
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
|
||||
/* ----------------------- MBAP Header --------------------------------------*/
|
||||
/*
|
||||
*
|
||||
* <------------------------ MODBUS TCP/IP ADU(1) ------------------------->
|
||||
* <----------- MODBUS PDU (1') ---------------->
|
||||
* +-----------+---------------+------------------------------------------+
|
||||
* | TID | PID | Length | UID |Code | Data |
|
||||
* +-----------+---------------+------------------------------------------+
|
||||
* | | | | |
|
||||
* (2) (3) (4) (5) (6)
|
||||
*
|
||||
* (2) ... MB_TCP_TID = 0 (Transaction Identifier - 2 Byte)
|
||||
* (3) ... MB_TCP_PID = 2 (Protocol Identifier - 2 Byte)
|
||||
* (4) ... MB_TCP_LEN = 4 (Number of bytes - 2 Byte)
|
||||
* (5) ... MB_TCP_UID = 6 (Unit Identifier - 1 Byte)
|
||||
* (6) ... MB_TCP_FUNC = 7 (Modbus Function Code)
|
||||
*
|
||||
* (1) ... Modbus TCP/IP Application Data Unit
|
||||
* (1') ... Modbus Protocol Data Unit
|
||||
*/
|
||||
|
||||
#define MB_TCP_TID 0
|
||||
#define MB_TCP_PID 2
|
||||
#define MB_TCP_LEN 4
|
||||
#define MB_TCP_UID 6
|
||||
#define MB_TCP_FUNC 7
|
||||
|
||||
#define MB_TCP_PROTOCOL_ID 0 /* 0 = Modbus Protocol */
|
||||
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
eMBErrorCode
|
||||
eMBTCPDoInit( USHORT ucTCPPort )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
|
||||
if( xMBTCPPortInit( ucTCPPort ) == FALSE )
|
||||
{
|
||||
eStatus = MB_EPORTERR;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
void
|
||||
eMBTCPStart( void )
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
eMBTCPStop( void )
|
||||
{
|
||||
/* Make sure that no more clients are connected. */
|
||||
vMBTCPPortDisable( );
|
||||
}
|
||||
|
||||
eMBErrorCode
|
||||
eMBTCPReceive( UCHAR * pucRcvAddress, UCHAR ** ppucFrame, USHORT * pusLength )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_EIO;
|
||||
UCHAR *pucMBTCPFrame;
|
||||
USHORT usLength;
|
||||
USHORT usPID;
|
||||
|
||||
if( xMBTCPPortGetRequest( &pucMBTCPFrame, &usLength ) != FALSE )
|
||||
{
|
||||
usPID = pucMBTCPFrame[MB_TCP_PID] << 8U;
|
||||
usPID |= pucMBTCPFrame[MB_TCP_PID + 1];
|
||||
|
||||
if( usPID == MB_TCP_PROTOCOL_ID )
|
||||
{
|
||||
*ppucFrame = &pucMBTCPFrame[MB_TCP_FUNC];
|
||||
*pusLength = usLength - MB_TCP_FUNC;
|
||||
eStatus = MB_ENOERR;
|
||||
|
||||
/* Modbus TCP does not use any addresses. Fake the source address such
|
||||
* that the processing part deals with this frame.
|
||||
*/
|
||||
*pucRcvAddress = MB_TCP_PSEUDO_ADDRESS;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EIO;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
eMBErrorCode
|
||||
eMBTCPSend( UCHAR _unused, const UCHAR * pucFrame, USHORT usLength )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
UCHAR *pucMBTCPFrame = ( UCHAR * ) pucFrame - MB_TCP_FUNC;
|
||||
USHORT usTCPLength = usLength + MB_TCP_FUNC;
|
||||
|
||||
/* The MBAP header is already initialized because the caller calls this
|
||||
* function with the buffer returned by the previous call. Therefore we
|
||||
* only have to update the length in the header. Note that the length
|
||||
* header includes the size of the Modbus PDU and the UID Byte. Therefore
|
||||
* the length is usLength plus one.
|
||||
*/
|
||||
pucMBTCPFrame[MB_TCP_LEN] = ( usLength + 1 ) >> 8U;
|
||||
pucMBTCPFrame[MB_TCP_LEN + 1] = ( usLength + 1 ) & 0xFF;
|
||||
if( xMBTCPPortSendResponse( pucMBTCPFrame, usTCPLength ) == FALSE )
|
||||
{
|
||||
eStatus = MB_EIO;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.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: mbtcp.h,v 1.2 2006/12/07 22:10:34 wolti Exp $
|
||||
*/
|
||||
|
||||
#ifndef _MB_TCP_H
|
||||
#define _MB_TCP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
#define MB_TCP_PSEUDO_ADDRESS 255
|
||||
|
||||
/* ----------------------- Function prototypes ------------------------------*/
|
||||
eMBErrorCode eMBTCPDoInit( USHORT ucTCPPort );
|
||||
void eMBTCPStart( void );
|
||||
void eMBTCPStop( void );
|
||||
eMBErrorCode eMBTCPReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame,
|
||||
USHORT * pusLength );
|
||||
eMBErrorCode eMBTCPSend( UCHAR _unused, const UCHAR * pucFrame,
|
||||
USHORT usLength );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: RT-Thread Port
|
||||
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
|
||||
*
|
||||
* 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.c,v 1.60 2015/02/01 9:18:05 Armink $
|
||||
*/
|
||||
|
||||
/* ----------------------- System includes --------------------------------*/
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "port.h"
|
||||
/* ----------------------- Variables ----------------------------------------*/
|
||||
static struct rt_semaphore lock;
|
||||
static int is_inited = 0;
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
void EnterCriticalSection(void)
|
||||
{
|
||||
rt_err_t err;
|
||||
if(!is_inited)
|
||||
{
|
||||
err = rt_sem_init(&lock, "fmb_lock", 1, RT_IPC_FLAG_PRIO);
|
||||
if(err != RT_EOK)
|
||||
{
|
||||
rt_kprintf("Freemodbus Critical init failed!\n");
|
||||
}
|
||||
is_inited = 1;
|
||||
}
|
||||
rt_sem_take(&lock, RT_WAITING_FOREVER);
|
||||
}
|
||||
|
||||
void ExitCriticalSection(void)
|
||||
{
|
||||
rt_sem_release(&lock);
|
||||
}
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: BARE Port
|
||||
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
|
||||
*
|
||||
* 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.60 2013/08/13 15:07:05 Armink add Master Functions $
|
||||
*/
|
||||
|
||||
#ifndef _PORT_H
|
||||
#define _PORT_H
|
||||
|
||||
#include "mbconfig.h"
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#define INLINE
|
||||
#define PR_BEGIN_EXTERN_C extern "C" {
|
||||
#define PR_END_EXTERN_C }
|
||||
|
||||
#define ENTER_CRITICAL_SECTION() EnterCriticalSection()
|
||||
#define EXIT_CRITICAL_SECTION() ExitCriticalSection()
|
||||
|
||||
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
|
||||
|
||||
void EnterCriticalSection(void);
|
||||
void ExitCriticalSection(void);
|
||||
|
||||
#endif
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: RT-Thread Port
|
||||
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
|
||||
*
|
||||
* 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.60 2013/08/13 15:07:05 Armink $
|
||||
*/
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mbport.h"
|
||||
|
||||
/* ----------------------- Variables ----------------------------------------*/
|
||||
static struct rt_event xSlaveOsEvent;
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
BOOL
|
||||
xMBPortEventInit( void )
|
||||
{
|
||||
rt_event_init(&xSlaveOsEvent,"slave event",RT_IPC_FLAG_PRIO);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBPortEventPost( eMBEventType eEvent )
|
||||
{
|
||||
rt_event_send(&xSlaveOsEvent, eEvent);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBPortEventGet( eMBEventType * eEvent )
|
||||
{
|
||||
rt_uint32_t recvedEvent;
|
||||
/* waiting forever OS event */
|
||||
rt_event_recv(&xSlaveOsEvent,
|
||||
EV_READY | EV_FRAME_RECEIVED | EV_EXECUTE | EV_FRAME_SENT,
|
||||
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER,
|
||||
&recvedEvent);
|
||||
switch (recvedEvent)
|
||||
{
|
||||
case EV_READY:
|
||||
*eEvent = EV_READY;
|
||||
break;
|
||||
case EV_FRAME_RECEIVED:
|
||||
*eEvent = EV_FRAME_RECEIVED;
|
||||
break;
|
||||
case EV_EXECUTE:
|
||||
*eEvent = EV_EXECUTE;
|
||||
break;
|
||||
case EV_FRAME_SENT:
|
||||
*eEvent = EV_FRAME_SENT;
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@@ -1,244 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: RT-Thread Port
|
||||
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
|
||||
*
|
||||
* 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_m.c v 1.60 2013/08/13 15:07:05 Armink add Master Functions$
|
||||
*/
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mb_m.h"
|
||||
#include "mbport.h"
|
||||
#include "port.h"
|
||||
|
||||
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
/* ----------------------- Variables ----------------------------------------*/
|
||||
static struct rt_semaphore xMasterRunRes;
|
||||
static struct rt_event xMasterOsEvent;
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
BOOL
|
||||
xMBMasterPortEventInit( void )
|
||||
{
|
||||
rt_event_init(&xMasterOsEvent,"master event",RT_IPC_FLAG_PRIO);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBMasterPortEventPost( eMBMasterEventType eEvent )
|
||||
{
|
||||
rt_event_send(&xMasterOsEvent, eEvent);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBMasterPortEventGet( eMBMasterEventType * eEvent )
|
||||
{
|
||||
rt_uint32_t recvedEvent;
|
||||
|
||||
/* waiting forever OS event */
|
||||
rt_event_recv(&xMasterOsEvent,
|
||||
EV_MASTER_READY | EV_MASTER_FRAME_RECEIVED | EV_MASTER_EXECUTE |
|
||||
EV_MASTER_FRAME_SENT | EV_MASTER_ERROR_PROCESS,
|
||||
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER,
|
||||
&recvedEvent);
|
||||
|
||||
/* the enum type couldn't convert to int type */
|
||||
switch (recvedEvent)
|
||||
{
|
||||
case EV_MASTER_READY:
|
||||
*eEvent = EV_MASTER_READY;
|
||||
break;
|
||||
case EV_MASTER_FRAME_RECEIVED:
|
||||
*eEvent = EV_MASTER_FRAME_RECEIVED;
|
||||
break;
|
||||
case EV_MASTER_EXECUTE:
|
||||
*eEvent = EV_MASTER_EXECUTE;
|
||||
break;
|
||||
case EV_MASTER_FRAME_SENT:
|
||||
*eEvent = EV_MASTER_FRAME_SENT;
|
||||
break;
|
||||
case EV_MASTER_ERROR_PROCESS:
|
||||
*eEvent = EV_MASTER_ERROR_PROCESS;
|
||||
break;
|
||||
default:
|
||||
*eEvent = EV_MASTER_FRAME_RECEIVED;
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
/**
|
||||
* This function is initialize the OS resource for modbus master.
|
||||
* Note:The resource is define by OS.If you not use OS this function can be empty.
|
||||
*
|
||||
*/
|
||||
void vMBMasterOsResInit( void )
|
||||
{
|
||||
rt_sem_init(&xMasterRunRes, "master res", 0x01 , RT_IPC_FLAG_PRIO);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is take Mobus Master running resource.
|
||||
* Note:The resource is define by Operating System.If you not use OS this function can be just return TRUE.
|
||||
*
|
||||
* @param lTimeOut the waiting time.
|
||||
*
|
||||
* @return resource taked result
|
||||
*/
|
||||
BOOL xMBMasterRunResTake( LONG lTimeOut )
|
||||
{
|
||||
/*If waiting time is -1 .It will wait forever */
|
||||
return rt_sem_take(&xMasterRunRes, lTimeOut) ? FALSE : TRUE ;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is release Mobus Master running resource.
|
||||
* Note:The resource is define by Operating System.If you not use OS this function can be empty.
|
||||
*
|
||||
*/
|
||||
void vMBMasterRunResRelease( void )
|
||||
{
|
||||
/* release resource */
|
||||
rt_sem_release(&xMasterRunRes);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is modbus master respond timeout error process callback function.
|
||||
* @note There functions will block modbus master poll while execute OS waiting.
|
||||
* So,for real-time of system.Do not execute too much waiting process.
|
||||
*
|
||||
* @param ucDestAddress destination salve address
|
||||
* @param pucPDUData PDU buffer data
|
||||
* @param ucPDULength PDU buffer length
|
||||
*
|
||||
*/
|
||||
void vMBMasterErrorCBRespondTimeout(UCHAR ucDestAddress, const UCHAR* pucPDUData,
|
||||
USHORT ucPDULength) {
|
||||
/**
|
||||
* @note This code is use OS's event mechanism for modbus master protocol stack.
|
||||
* If you don't use OS, you can change it.
|
||||
*/
|
||||
rt_event_send(&xMasterOsEvent, EV_MASTER_ERROR_RESPOND_TIMEOUT);
|
||||
|
||||
/* You can add your code under here. */
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This is modbus master receive data error process callback function.
|
||||
* @note There functions will block modbus master poll while execute OS waiting.
|
||||
* So,for real-time of system.Do not execute too much waiting process.
|
||||
*
|
||||
* @param ucDestAddress destination salve address
|
||||
* @param pucPDUData PDU buffer data
|
||||
* @param ucPDULength PDU buffer length
|
||||
*
|
||||
*/
|
||||
void vMBMasterErrorCBReceiveData(UCHAR ucDestAddress, const UCHAR* pucPDUData,
|
||||
USHORT ucPDULength) {
|
||||
/**
|
||||
* @note This code is use OS's event mechanism for modbus master protocol stack.
|
||||
* If you don't use OS, you can change it.
|
||||
*/
|
||||
rt_event_send(&xMasterOsEvent, EV_MASTER_ERROR_RECEIVE_DATA);
|
||||
|
||||
/* You can add your code under here. */
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This is modbus master execute function error process callback function.
|
||||
* @note There functions will block modbus master poll while execute OS waiting.
|
||||
* So,for real-time of system.Do not execute too much waiting process.
|
||||
*
|
||||
* @param ucDestAddress destination salve address
|
||||
* @param pucPDUData PDU buffer data
|
||||
* @param ucPDULength PDU buffer length
|
||||
*
|
||||
*/
|
||||
void vMBMasterErrorCBExecuteFunction(UCHAR ucDestAddress, const UCHAR* pucPDUData,
|
||||
USHORT ucPDULength) {
|
||||
/**
|
||||
* @note This code is use OS's event mechanism for modbus master protocol stack.
|
||||
* If you don't use OS, you can change it.
|
||||
*/
|
||||
rt_event_send(&xMasterOsEvent, EV_MASTER_ERROR_EXECUTE_FUNCTION);
|
||||
|
||||
/* You can add your code under here. */
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This is modbus master request process success callback function.
|
||||
* @note There functions will block modbus master poll while execute OS waiting.
|
||||
* So,for real-time of system.Do not execute too much waiting process.
|
||||
*
|
||||
*/
|
||||
void vMBMasterCBRequestScuuess( void ) {
|
||||
/**
|
||||
* @note This code is use OS's event mechanism for modbus master protocol stack.
|
||||
* If you don't use OS, you can change it.
|
||||
*/
|
||||
rt_event_send(&xMasterOsEvent, EV_MASTER_PROCESS_SUCESS);
|
||||
|
||||
/* You can add your code under here. */
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is wait for modbus master request finish and return result.
|
||||
* Waiting result include request process success, request respond timeout,
|
||||
* receive data error and execute function error.You can use the above callback function.
|
||||
* @note If you are use OS, you can use OS's event mechanism. Otherwise you have to run
|
||||
* much user custom delay for waiting.
|
||||
*
|
||||
* @return request error code
|
||||
*/
|
||||
eMBMasterReqErrCode eMBMasterWaitRequestFinish( void ) {
|
||||
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
|
||||
rt_uint32_t recvedEvent;
|
||||
/* waiting for OS event */
|
||||
rt_event_recv(&xMasterOsEvent,
|
||||
EV_MASTER_PROCESS_SUCESS | EV_MASTER_ERROR_RESPOND_TIMEOUT
|
||||
| EV_MASTER_ERROR_RECEIVE_DATA
|
||||
| EV_MASTER_ERROR_EXECUTE_FUNCTION,
|
||||
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER,
|
||||
&recvedEvent);
|
||||
switch (recvedEvent)
|
||||
{
|
||||
case EV_MASTER_PROCESS_SUCESS:
|
||||
break;
|
||||
case EV_MASTER_ERROR_RESPOND_TIMEOUT:
|
||||
{
|
||||
eErrStatus = MB_MRE_TIMEDOUT;
|
||||
break;
|
||||
}
|
||||
case EV_MASTER_ERROR_RECEIVE_DATA:
|
||||
{
|
||||
eErrStatus = MB_MRE_REV_DATA;
|
||||
break;
|
||||
}
|
||||
case EV_MASTER_ERROR_EXECUTE_FUNCTION:
|
||||
{
|
||||
eErrStatus = MB_MRE_EXE_FUN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return eErrStatus;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,233 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: RT-Thread Port
|
||||
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
|
||||
*
|
||||
* 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_m.c,v 1.60 2013/08/13 15:07:05 Armink add Master Functions $
|
||||
*/
|
||||
|
||||
#include "port.h"
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mbport.h"
|
||||
#include "rtdevice.h"
|
||||
#include "board.h"
|
||||
|
||||
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
|
||||
/* ----------------------- Static variables ---------------------------------*/
|
||||
/* software simulation serial transmit IRQ handler thread stack */
|
||||
#ifdef rt_align
|
||||
rt_align(RT_ALIGN_SIZE)
|
||||
#else
|
||||
ALIGN(RT_ALIGN_SIZE)
|
||||
#endif
|
||||
static rt_uint8_t serial_soft_trans_irq_stack[512];
|
||||
/* software simulation serial transmit IRQ handler thread */
|
||||
static struct rt_thread thread_serial_soft_trans_irq;
|
||||
/* serial event */
|
||||
static struct rt_event event_serial;
|
||||
/* modbus master serial device */
|
||||
static struct rt_serial_device *serial;
|
||||
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
/* serial transmit event */
|
||||
#define EVENT_SERIAL_TRANS_START (1<<0)
|
||||
|
||||
/* ----------------------- static functions ---------------------------------*/
|
||||
static void prvvUARTTxReadyISR(void);
|
||||
static void prvvUARTRxISR(void);
|
||||
static rt_err_t serial_rx_ind(rt_device_t dev, rt_size_t size);
|
||||
static void serial_soft_trans_irq(void* parameter);
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
BOOL xMBMasterPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
|
||||
eMBParity eParity)
|
||||
{
|
||||
rt_device_t dev = RT_NULL;
|
||||
char uart_name[20];
|
||||
|
||||
/**
|
||||
* set 485 mode receive and transmit control IO
|
||||
* @note MODBUS_MASTER_RT_CONTROL_PIN_INDEX need be defined by user
|
||||
*/
|
||||
#if defined(RT_MODBUS_MASTER_USE_CONTROL_PIN)
|
||||
rt_pin_mode(MODBUS_MASTER_RT_CONTROL_PIN_INDEX, PIN_MODE_OUTPUT);
|
||||
#endif
|
||||
/* set serial name */
|
||||
rt_snprintf(uart_name,sizeof(uart_name), "uart%d", ucPORT);
|
||||
|
||||
dev = rt_device_find(uart_name);
|
||||
if(dev == RT_NULL)
|
||||
{
|
||||
/* can not find uart */
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
serial = (struct rt_serial_device*)dev;
|
||||
}
|
||||
|
||||
/* set serial configure parameter */
|
||||
serial->config.baud_rate = ulBaudRate;
|
||||
serial->config.stop_bits = STOP_BITS_1;
|
||||
switch(eParity){
|
||||
case MB_PAR_NONE: {
|
||||
serial->config.data_bits = DATA_BITS_8;
|
||||
serial->config.parity = PARITY_NONE;
|
||||
break;
|
||||
}
|
||||
case MB_PAR_ODD: {
|
||||
serial->config.data_bits = DATA_BITS_9;
|
||||
serial->config.parity = PARITY_ODD;
|
||||
break;
|
||||
}
|
||||
case MB_PAR_EVEN: {
|
||||
serial->config.data_bits = DATA_BITS_9;
|
||||
serial->config.parity = PARITY_EVEN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* set serial configure */
|
||||
serial->ops->configure(serial, &(serial->config));
|
||||
|
||||
/* open serial device */
|
||||
if (!rt_device_open(&serial->parent, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX)) {
|
||||
rt_device_set_rx_indicate(&serial->parent, serial_rx_ind);
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* software initialize */
|
||||
rt_event_init(&event_serial, "master event", RT_IPC_FLAG_PRIO);
|
||||
rt_thread_init(&thread_serial_soft_trans_irq,
|
||||
"master trans",
|
||||
serial_soft_trans_irq,
|
||||
RT_NULL,
|
||||
serial_soft_trans_irq_stack,
|
||||
sizeof(serial_soft_trans_irq_stack),
|
||||
10, 5);
|
||||
rt_thread_startup(&thread_serial_soft_trans_irq);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void vMBMasterPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable)
|
||||
{
|
||||
rt_uint32_t recved_event;
|
||||
if (xRxEnable)
|
||||
{
|
||||
/* enable RX interrupt */
|
||||
serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX);
|
||||
/* switch 485 to receive mode */
|
||||
#if defined(RT_MODBUS_MASTER_USE_CONTROL_PIN)
|
||||
rt_pin_write(MODBUS_MASTER_RT_CONTROL_PIN_INDEX, PIN_LOW);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
/* switch 485 to transmit mode */
|
||||
#if defined(RT_MODBUS_MASTER_USE_CONTROL_PIN)
|
||||
rt_pin_write(MODBUS_MASTER_RT_CONTROL_PIN_INDEX, PIN_HIGH);
|
||||
#endif
|
||||
/* disable RX interrupt */
|
||||
serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_FLAG_INT_RX);
|
||||
}
|
||||
if (xTxEnable)
|
||||
{
|
||||
/* start serial transmit */
|
||||
rt_event_send(&event_serial, EVENT_SERIAL_TRANS_START);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* stop serial transmit */
|
||||
rt_event_recv(&event_serial, EVENT_SERIAL_TRANS_START,
|
||||
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, 0,
|
||||
&recved_event);
|
||||
}
|
||||
}
|
||||
|
||||
void vMBMasterPortClose(void)
|
||||
{
|
||||
serial->parent.close(&(serial->parent));
|
||||
}
|
||||
|
||||
BOOL xMBMasterPortSerialPutByte(CHAR ucByte)
|
||||
{
|
||||
serial->parent.write(&(serial->parent), 0, &ucByte, 1);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL xMBMasterPortSerialGetByte(CHAR * pucByte)
|
||||
{
|
||||
serial->parent.read(&(serial->parent), 0, pucByte, 1);
|
||||
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.
|
||||
*/
|
||||
void prvvUARTTxReadyISR(void)
|
||||
{
|
||||
pxMBMasterFrameCBTransmitterEmpty();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
void prvvUARTRxISR(void)
|
||||
{
|
||||
pxMBMasterFrameCBByteReceived();
|
||||
}
|
||||
|
||||
/**
|
||||
* Software simulation serial transmit IRQ handler.
|
||||
*
|
||||
* @param parameter parameter
|
||||
*/
|
||||
static void serial_soft_trans_irq(void* parameter) {
|
||||
rt_uint32_t recved_event;
|
||||
while (1)
|
||||
{
|
||||
/* waiting for serial transmit start */
|
||||
rt_event_recv(&event_serial, EVENT_SERIAL_TRANS_START, RT_EVENT_FLAG_OR,
|
||||
RT_WAITING_FOREVER, &recved_event);
|
||||
/* execute modbus callback */
|
||||
prvvUARTTxReadyISR();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is serial receive callback function
|
||||
*
|
||||
* @param dev the device of serial
|
||||
* @param size the data size that receive
|
||||
*
|
||||
* @return return RT_EOK
|
||||
*/
|
||||
static rt_err_t serial_rx_ind(rt_device_t dev, rt_size_t size) {
|
||||
prvvUARTRxISR();
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,134 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: RT-Thread Port
|
||||
* Copyright (C) 2019 flybreak <guozhanxin@rt-thread.com>
|
||||
*
|
||||
* 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.60 2019/07/11 17:04:32 flybreak $
|
||||
*/
|
||||
|
||||
#include "port.h"
|
||||
|
||||
#ifdef PKG_MODBUS_SLAVE_TCP
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mbport.h"
|
||||
#include "tcpserver.h"
|
||||
|
||||
/* ----------------------- Defines -----------------------------------------*/
|
||||
#define MB_TCP_DEFAULT_PORT 502
|
||||
#define MB_TCP_BUF_SIZE ( 256 + 7 )
|
||||
|
||||
/* ----------------------- Static variables ---------------------------------*/
|
||||
static tcpclient_t mb_client;
|
||||
static UCHAR prvvTCPBuf[MB_TCP_BUF_SIZE];
|
||||
static USHORT prvvTCPLength;
|
||||
|
||||
static void tcpserver_event_notify(tcpclient_t client, rt_uint8_t event)
|
||||
{
|
||||
static rt_tick_t recv_tick = 0;
|
||||
switch (event)
|
||||
{
|
||||
case TCPSERVER_EVENT_CONNECT:
|
||||
if (mb_client == RT_NULL)
|
||||
{
|
||||
mb_client = client;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(rt_tick_get() - recv_tick > 30 * RT_TICK_PER_SECOND) /* set timeout as 30s */
|
||||
{
|
||||
tcpserver_close(mb_client);
|
||||
mb_client = client;
|
||||
recv_tick = rt_tick_get();
|
||||
}
|
||||
else
|
||||
{
|
||||
tcpserver_close(client);
|
||||
rt_kprintf("Multi-host is not supported, please disconnect the current host first!\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TCPSERVER_EVENT_RECV:
|
||||
if( mb_client == client)
|
||||
{
|
||||
recv_tick = rt_tick_get();
|
||||
prvvTCPLength = tcpserver_recv(mb_client, &prvvTCPBuf, MB_TCP_BUF_SIZE, 100);
|
||||
if (prvvTCPLength)
|
||||
{
|
||||
xMBPortEventPost(EV_FRAME_RECEIVED);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TCPSERVER_EVENT_DISCONNECT:
|
||||
if (mb_client == client)
|
||||
mb_client = RT_NULL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBTCPPortInit(USHORT usTCPPort)
|
||||
{
|
||||
struct tcpserver *serv;
|
||||
|
||||
if (usTCPPort == 0)
|
||||
usTCPPort = MB_TCP_DEFAULT_PORT;
|
||||
|
||||
serv = tcpserver_create(0, usTCPPort);
|
||||
|
||||
tcpserver_set_notify_callback(serv, tcpserver_event_notify);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
vMBTCPPortClose(void)
|
||||
{
|
||||
tcpserver_destroy(mb_client->server);
|
||||
}
|
||||
|
||||
void
|
||||
vMBTCPPortDisable(void)
|
||||
{
|
||||
tcpserver_close(mb_client);
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBTCPPortGetRequest(UCHAR **ppucMBTCPFrame, USHORT *usTCPLength)
|
||||
{
|
||||
*ppucMBTCPFrame = &prvvTCPBuf[0];
|
||||
*usTCPLength = prvvTCPLength;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL
|
||||
xMBTCPPortSendResponse(const UCHAR *pucMBTCPFrame, USHORT usTCPLength)
|
||||
{
|
||||
rt_int16_t ret;
|
||||
BOOL bFrameSent = FALSE;
|
||||
|
||||
if (mb_client)
|
||||
{
|
||||
ret = tcpserver_send(mb_client, (void *)pucMBTCPFrame, usTCPLength, 0);
|
||||
if (ret == usTCPLength)
|
||||
bFrameSent = TRUE;
|
||||
}
|
||||
return bFrameSent;
|
||||
}
|
||||
#endif
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: RT-Thread Port
|
||||
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
|
||||
*
|
||||
* 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.60 2013/08/13 15:07:05 Armink $
|
||||
*/
|
||||
|
||||
/* ----------------------- Platform includes --------------------------------*/
|
||||
#include "port.h"
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mbport.h"
|
||||
|
||||
/* ----------------------- static functions ---------------------------------*/
|
||||
static struct rt_timer timer;
|
||||
static void prvvTIMERExpiredISR(void);
|
||||
static void timer_timeout_ind(void* parameter);
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
BOOL xMBPortTimersInit(USHORT usTim1Timerout50us)
|
||||
{
|
||||
rt_timer_init(&timer, "slave timer",
|
||||
timer_timeout_ind, /* bind timeout callback function */
|
||||
RT_NULL,
|
||||
(50 * usTim1Timerout50us) / (1000 * 1000 / RT_TICK_PER_SECOND) + 1,
|
||||
RT_TIMER_FLAG_ONE_SHOT); /* one shot */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void vMBPortTimersEnable()
|
||||
{
|
||||
rt_timer_start(&timer);
|
||||
}
|
||||
|
||||
void vMBPortTimersDisable()
|
||||
{
|
||||
rt_timer_stop(&timer);
|
||||
}
|
||||
|
||||
void prvvTIMERExpiredISR(void)
|
||||
{
|
||||
(void) pxMBPortCBTimerExpired();
|
||||
}
|
||||
|
||||
static void timer_timeout_ind(void* parameter)
|
||||
{
|
||||
prvvTIMERExpiredISR();
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: RT-Thread Port
|
||||
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
|
||||
*
|
||||
* 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_m.c,v 1.60 2013/08/13 15:07:05 Armink add Master Functions$
|
||||
*/
|
||||
|
||||
/* ----------------------- Platform includes --------------------------------*/
|
||||
#include "port.h"
|
||||
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mb_m.h"
|
||||
#include "mbport.h"
|
||||
|
||||
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
|
||||
/* ----------------------- Variables ----------------------------------------*/
|
||||
static USHORT usT35TimeOut50us;
|
||||
static struct rt_timer timer;
|
||||
static void prvvTIMERExpiredISR(void);
|
||||
static void timer_timeout_ind(void* parameter);
|
||||
|
||||
/* ----------------------- static functions ---------------------------------*/
|
||||
static void prvvTIMERExpiredISR(void);
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
BOOL xMBMasterPortTimersInit(USHORT usTimeOut50us)
|
||||
{
|
||||
/* backup T35 ticks */
|
||||
usT35TimeOut50us = usTimeOut50us;
|
||||
|
||||
rt_timer_init(&timer, "master timer",
|
||||
timer_timeout_ind, /* bind timeout callback function */
|
||||
RT_NULL,
|
||||
(50 * usT35TimeOut50us) / (1000 * 1000 / RT_TICK_PER_SECOND) + 1,
|
||||
RT_TIMER_FLAG_ONE_SHOT); /* one shot */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void vMBMasterPortTimersT35Enable()
|
||||
{
|
||||
rt_tick_t timer_tick = (50 * usT35TimeOut50us)
|
||||
/ (1000 * 1000 / RT_TICK_PER_SECOND) + 1;
|
||||
|
||||
/* Set current timer mode, don't change it.*/
|
||||
vMBMasterSetCurTimerMode(MB_TMODE_T35);
|
||||
|
||||
rt_timer_control(&timer, RT_TIMER_CTRL_SET_TIME, &timer_tick);
|
||||
|
||||
rt_timer_start(&timer);
|
||||
}
|
||||
|
||||
void vMBMasterPortTimersConvertDelayEnable()
|
||||
{
|
||||
rt_tick_t timer_tick = MB_MASTER_DELAY_MS_CONVERT * RT_TICK_PER_SECOND / 1000;
|
||||
|
||||
/* Set current timer mode, don't change it.*/
|
||||
vMBMasterSetCurTimerMode(MB_TMODE_CONVERT_DELAY);
|
||||
|
||||
rt_timer_control(&timer, RT_TIMER_CTRL_SET_TIME, &timer_tick);
|
||||
|
||||
rt_timer_start(&timer);
|
||||
}
|
||||
|
||||
void vMBMasterPortTimersRespondTimeoutEnable()
|
||||
{
|
||||
rt_tick_t timer_tick = MB_MASTER_TIMEOUT_MS_RESPOND * RT_TICK_PER_SECOND / 1000;
|
||||
|
||||
/* Set current timer mode, don't change it.*/
|
||||
vMBMasterSetCurTimerMode(MB_TMODE_RESPOND_TIMEOUT);
|
||||
|
||||
rt_timer_control(&timer, RT_TIMER_CTRL_SET_TIME, &timer_tick);
|
||||
|
||||
rt_timer_start(&timer);
|
||||
}
|
||||
|
||||
void vMBMasterPortTimersDisable()
|
||||
{
|
||||
rt_timer_stop(&timer);
|
||||
}
|
||||
|
||||
void prvvTIMERExpiredISR(void)
|
||||
{
|
||||
(void) pxMBMasterPortCBTimerExpired();
|
||||
}
|
||||
|
||||
static void timer_timeout_ind(void* parameter)
|
||||
{
|
||||
prvvTIMERExpiredISR();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,46 +0,0 @@
|
||||
#ifndef USER_APP
|
||||
#define USER_APP
|
||||
/* ----------------------- Modbus includes ----------------------------------*/
|
||||
#include "mb.h"
|
||||
#include "mb_m.h"
|
||||
#include "mbconfig.h"
|
||||
#include "mbframe.h"
|
||||
#include "mbutils.h"
|
||||
|
||||
/* -----------------------Slave Defines -------------------------------------*/
|
||||
#define S_DISCRETE_INPUT_START RT_S_DISCRETE_INPUT_START
|
||||
#define S_DISCRETE_INPUT_NDISCRETES RT_S_DISCRETE_INPUT_NDISCRETES
|
||||
#define S_COIL_START RT_S_COIL_START
|
||||
#define S_COIL_NCOILS RT_S_COIL_NCOILS
|
||||
#define S_REG_INPUT_START RT_S_REG_INPUT_START
|
||||
#define S_REG_INPUT_NREGS RT_S_REG_INPUT_NREGS
|
||||
#define S_REG_HOLDING_START RT_S_REG_HOLDING_START
|
||||
#define S_REG_HOLDING_NREGS RT_S_REG_HOLDING_NREGS
|
||||
/* salve mode: holding register's all address */
|
||||
#define S_HD_RESERVE RT_S_HD_RESERVE
|
||||
/* salve mode: input register's all address */
|
||||
#define S_IN_RESERVE RT_S_IN_RESERVE
|
||||
/* salve mode: coil's all address */
|
||||
#define S_CO_RESERVE RT_S_CO_RESERVE
|
||||
/* salve mode: discrete's all address */
|
||||
#define S_DI_RESERVE RT_S_DI_RESERVE
|
||||
|
||||
/* -----------------------Master Defines -------------------------------------*/
|
||||
#define M_DISCRETE_INPUT_START RT_M_DISCRETE_INPUT_START
|
||||
#define M_DISCRETE_INPUT_NDISCRETES RT_M_DISCRETE_INPUT_NDISCRETES
|
||||
#define M_COIL_START RT_M_COIL_START
|
||||
#define M_COIL_NCOILS RT_M_COIL_NCOILS
|
||||
#define M_REG_INPUT_START RT_M_REG_INPUT_START
|
||||
#define M_REG_INPUT_NREGS RT_M_REG_INPUT_NREGS
|
||||
#define M_REG_HOLDING_START RT_M_REG_HOLDING_START
|
||||
#define M_REG_HOLDING_NREGS RT_M_REG_HOLDING_NREGS
|
||||
/* master mode: holding register's all address */
|
||||
#define M_HD_RESERVE RT_M_HD_RESERVE
|
||||
/* master mode: input register's all address */
|
||||
#define M_IN_RESERVE RT_M_IN_RESERVE
|
||||
/* master mode: coil's all address */
|
||||
#define M_CO_RESERVE RT_M_CO_RESERVE
|
||||
/* master mode: discrete's all address */
|
||||
#define M_DI_RESERVE RT_M_DI_RESERVE
|
||||
|
||||
#endif
|
||||
@@ -1,294 +0,0 @@
|
||||
/*
|
||||
* FreeModbus Libary: user callback functions and buffer define in master mode
|
||||
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
|
||||
*
|
||||
* 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: user_mb_app_m.c,v 1.60 2013/11/23 11:49:05 Armink $
|
||||
*/
|
||||
#include "user_mb_app.h"
|
||||
|
||||
/*-----------------------Master mode use these variables----------------------*/
|
||||
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
|
||||
//Master mode:DiscreteInputs variables
|
||||
USHORT usMDiscInStart = M_DISCRETE_INPUT_START;
|
||||
#if M_DISCRETE_INPUT_NDISCRETES%8
|
||||
UCHAR ucMDiscInBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_DISCRETE_INPUT_NDISCRETES/8+1];
|
||||
#else
|
||||
UCHAR ucMDiscInBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_DISCRETE_INPUT_NDISCRETES/8];
|
||||
#endif
|
||||
//Master mode:Coils variables
|
||||
USHORT usMCoilStart = M_COIL_START;
|
||||
#if M_COIL_NCOILS%8
|
||||
UCHAR ucMCoilBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_COIL_NCOILS/8+1];
|
||||
#else
|
||||
UCHAR ucMCoilBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_COIL_NCOILS/8];
|
||||
#endif
|
||||
//Master mode:InputRegister variables
|
||||
USHORT usMRegInStart = M_REG_INPUT_START;
|
||||
USHORT usMRegInBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_REG_INPUT_NREGS];
|
||||
//Master mode:HoldingRegister variables
|
||||
USHORT usMRegHoldStart = M_REG_HOLDING_START;
|
||||
USHORT usMRegHoldBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_REG_HOLDING_NREGS];
|
||||
|
||||
/**
|
||||
* Modbus master input register callback function.
|
||||
*
|
||||
* @param pucRegBuffer input register buffer
|
||||
* @param usAddress input register address
|
||||
* @param usNRegs input register number
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
eMBErrorCode eMBMasterRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
USHORT iRegIndex;
|
||||
USHORT * pusRegInputBuf;
|
||||
USHORT REG_INPUT_START;
|
||||
USHORT REG_INPUT_NREGS;
|
||||
USHORT usRegInStart;
|
||||
|
||||
pusRegInputBuf = usMRegInBuf[ucMBMasterGetDestAddress() - 1];
|
||||
REG_INPUT_START = M_REG_INPUT_START;
|
||||
REG_INPUT_NREGS = M_REG_INPUT_NREGS;
|
||||
usRegInStart = usMRegInStart;
|
||||
|
||||
/* it already plus one in modbus function method. */
|
||||
usAddress--;
|
||||
|
||||
if ((usAddress >= REG_INPUT_START)
|
||||
&& (usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS))
|
||||
{
|
||||
iRegIndex = usAddress - usRegInStart;
|
||||
while (usNRegs > 0)
|
||||
{
|
||||
pusRegInputBuf[iRegIndex] = *pucRegBuffer++ << 8;
|
||||
pusRegInputBuf[iRegIndex] |= *pucRegBuffer++;
|
||||
iRegIndex++;
|
||||
usNRegs--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_ENOREG;
|
||||
}
|
||||
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modbus master holding register callback function.
|
||||
*
|
||||
* @param pucRegBuffer holding register buffer
|
||||
* @param usAddress holding register address
|
||||
* @param usNRegs holding register number
|
||||
* @param eMode read or write
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
eMBErrorCode eMBMasterRegHoldingCB(UCHAR * pucRegBuffer, USHORT usAddress,
|
||||
USHORT usNRegs, eMBRegisterMode eMode)
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
USHORT iRegIndex;
|
||||
USHORT * pusRegHoldingBuf;
|
||||
USHORT REG_HOLDING_START;
|
||||
USHORT REG_HOLDING_NREGS;
|
||||
USHORT usRegHoldStart;
|
||||
|
||||
pusRegHoldingBuf = usMRegHoldBuf[ucMBMasterGetDestAddress() - 1];
|
||||
REG_HOLDING_START = M_REG_HOLDING_START;
|
||||
REG_HOLDING_NREGS = M_REG_HOLDING_NREGS;
|
||||
usRegHoldStart = usMRegHoldStart;
|
||||
/* if mode is read, the master will write the received date to buffer. */
|
||||
eMode = MB_REG_WRITE;
|
||||
|
||||
/* it already plus one in modbus function method. */
|
||||
usAddress--;
|
||||
|
||||
if ((usAddress >= REG_HOLDING_START)
|
||||
&& (usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS))
|
||||
{
|
||||
iRegIndex = usAddress - usRegHoldStart;
|
||||
switch (eMode)
|
||||
{
|
||||
/* read current register values from the protocol stack. */
|
||||
case MB_REG_READ:
|
||||
while (usNRegs > 0)
|
||||
{
|
||||
*pucRegBuffer++ = (UCHAR) (pusRegHoldingBuf[iRegIndex] >> 8);
|
||||
*pucRegBuffer++ = (UCHAR) (pusRegHoldingBuf[iRegIndex] & 0xFF);
|
||||
iRegIndex++;
|
||||
usNRegs--;
|
||||
}
|
||||
break;
|
||||
/* write current register values with new values from the protocol stack. */
|
||||
case MB_REG_WRITE:
|
||||
while (usNRegs > 0)
|
||||
{
|
||||
pusRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
|
||||
pusRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
|
||||
iRegIndex++;
|
||||
usNRegs--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_ENOREG;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modbus master coils callback function.
|
||||
*
|
||||
* @param pucRegBuffer coils buffer
|
||||
* @param usAddress coils address
|
||||
* @param usNCoils coils number
|
||||
* @param eMode read or write
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
eMBErrorCode eMBMasterRegCoilsCB(UCHAR * pucRegBuffer, USHORT usAddress,
|
||||
USHORT usNCoils, eMBRegisterMode eMode)
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
USHORT iRegIndex , iRegBitIndex , iNReg;
|
||||
UCHAR * pucCoilBuf;
|
||||
USHORT COIL_START;
|
||||
USHORT COIL_NCOILS;
|
||||
USHORT usCoilStart;
|
||||
iNReg = usNCoils / 8 + 1;
|
||||
|
||||
pucCoilBuf = ucMCoilBuf[ucMBMasterGetDestAddress() - 1];
|
||||
COIL_START = M_COIL_START;
|
||||
COIL_NCOILS = M_COIL_NCOILS;
|
||||
usCoilStart = usMCoilStart;
|
||||
|
||||
/* if mode is read,the master will write the received date to buffer. */
|
||||
eMode = MB_REG_WRITE;
|
||||
|
||||
/* it already plus one in modbus function method. */
|
||||
usAddress--;
|
||||
|
||||
if ((usAddress >= COIL_START)
|
||||
&& (usAddress + usNCoils <= COIL_START + COIL_NCOILS))
|
||||
{
|
||||
iRegIndex = (USHORT) (usAddress - usCoilStart) / 8;
|
||||
iRegBitIndex = (USHORT) (usAddress - usCoilStart) % 8;
|
||||
switch (eMode)
|
||||
{
|
||||
/* read current coil values from the protocol stack. */
|
||||
case MB_REG_READ:
|
||||
while (iNReg > 0)
|
||||
{
|
||||
*pucRegBuffer++ = xMBUtilGetBits(&pucCoilBuf[iRegIndex++],
|
||||
iRegBitIndex, 8);
|
||||
iNReg--;
|
||||
}
|
||||
pucRegBuffer--;
|
||||
/* last coils */
|
||||
usNCoils = usNCoils % 8;
|
||||
/* filling zero to high bit */
|
||||
*pucRegBuffer = *pucRegBuffer << (8 - usNCoils);
|
||||
*pucRegBuffer = *pucRegBuffer >> (8 - usNCoils);
|
||||
break;
|
||||
|
||||
/* write current coil values with new values from the protocol stack. */
|
||||
case MB_REG_WRITE:
|
||||
while (iNReg > 1)
|
||||
{
|
||||
xMBUtilSetBits(&pucCoilBuf[iRegIndex++], iRegBitIndex, 8,
|
||||
*pucRegBuffer++);
|
||||
iNReg--;
|
||||
}
|
||||
/* last coils */
|
||||
usNCoils = usNCoils % 8;
|
||||
/* xMBUtilSetBits has bug when ucNBits is zero */
|
||||
if (usNCoils != 0)
|
||||
{
|
||||
xMBUtilSetBits(&pucCoilBuf[iRegIndex++], iRegBitIndex, usNCoils,
|
||||
*pucRegBuffer++);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_ENOREG;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modbus master discrete callback function.
|
||||
*
|
||||
* @param pucRegBuffer discrete buffer
|
||||
* @param usAddress discrete address
|
||||
* @param usNDiscrete discrete number
|
||||
*
|
||||
* @return result
|
||||
*/
|
||||
eMBErrorCode eMBMasterRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
USHORT iRegIndex , iRegBitIndex , iNReg;
|
||||
UCHAR * pucDiscreteInputBuf;
|
||||
USHORT DISCRETE_INPUT_START;
|
||||
USHORT DISCRETE_INPUT_NDISCRETES;
|
||||
USHORT usDiscreteInputStart;
|
||||
iNReg = usNDiscrete / 8 + 1;
|
||||
|
||||
pucDiscreteInputBuf = ucMDiscInBuf[ucMBMasterGetDestAddress() - 1];
|
||||
DISCRETE_INPUT_START = M_DISCRETE_INPUT_START;
|
||||
DISCRETE_INPUT_NDISCRETES = M_DISCRETE_INPUT_NDISCRETES;
|
||||
usDiscreteInputStart = usMDiscInStart;
|
||||
|
||||
/* it already plus one in modbus function method. */
|
||||
usAddress--;
|
||||
|
||||
if ((usAddress >= DISCRETE_INPUT_START)
|
||||
&& (usAddress + usNDiscrete <= DISCRETE_INPUT_START + DISCRETE_INPUT_NDISCRETES))
|
||||
{
|
||||
iRegIndex = (USHORT) (usAddress - usDiscreteInputStart) / 8;
|
||||
iRegBitIndex = (USHORT) (usAddress - usDiscreteInputStart) % 8;
|
||||
|
||||
/* write current discrete values with new values from the protocol stack. */
|
||||
while (iNReg > 1)
|
||||
{
|
||||
xMBUtilSetBits(&pucDiscreteInputBuf[iRegIndex++], iRegBitIndex, 8,
|
||||
*pucRegBuffer++);
|
||||
iNReg--;
|
||||
}
|
||||
/* last discrete */
|
||||
usNDiscrete = usNDiscrete % 8;
|
||||
/* xMBUtilSetBits has bug when ucNBits is zero */
|
||||
if (usNDiscrete != 0)
|
||||
{
|
||||
xMBUtilSetBits(&pucDiscreteInputBuf[iRegIndex++], iRegBitIndex,
|
||||
usNDiscrete, *pucRegBuffer++);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_ENOREG;
|
||||
}
|
||||
|
||||
return eStatus;
|
||||
}
|
||||
#endif
|
||||
@@ -1,57 +0,0 @@
|
||||
# 示例代码说明
|
||||
|
||||
## 运行方法
|
||||
|
||||
### 配置工程
|
||||
|
||||
使用 Freemodbus 软件包示例代码,需要在 RT-Thread 的包管理器中选择它,并根据需要进行配置,具体路径如下:
|
||||
|
||||
```
|
||||
RT-Thread online packages
|
||||
IoT - internet of things --->
|
||||
[*] FreeModbus: Modbus master and slave stack --->
|
||||
[*] Master mode --->
|
||||
[*] Enable RTU master mode
|
||||
[*] Enable master sample
|
||||
(1) Test slave device address
|
||||
(2) uart number used by master sample, e.g. 2 means uart2
|
||||
(115200) uart baudrate used by master sample
|
||||
[*] Slave mode --->
|
||||
[*] Enable RTU slave mode
|
||||
[ ] Enable ASCII slave mode
|
||||
[ ] Use Contorl Pin
|
||||
[*] Enable slave sample
|
||||
(1) Slave device address
|
||||
(2) uart number used by slave sample, e.g. 2 means uart2
|
||||
(115200) uart baudrate used by slave sample
|
||||
```
|
||||
|
||||
添加示例代码到工程中,并编译下载之后,可以在控制台中看到这两个命令,分别是 Modbus 主机和从机的示例代码。要看代码运行的效果还需要 PC 端 Modbus Poll 和 Modbus slave 这两个软件的配合。
|
||||
|
||||

|
||||
|
||||
### 运行主机示例
|
||||
|
||||
首先下载安装和主机示例代码配合的 Modbus slave 软件。
|
||||
|
||||
然后,在命令行输入 `mb_master_sample` 命令就可以运行主机的示例代码。
|
||||
|
||||
运行之后,打开 Modbus slave 软件,点击菜单“Setup”中“Slave Definition.. F2”进行参数设置。
|
||||
|
||||

|
||||
|
||||
点击菜单“Connection”中“Connect.. F3”进行连接。弹出连接对话框,根据具体情况配置:
|
||||
|
||||

|
||||
|
||||
连接成功,可以看到寄存器列表中的第 2、3个寄存器的数值在不断变化。
|
||||
|
||||

|
||||
|
||||
### 运行从机示例
|
||||
|
||||
从机的运行示例和主机相差不大,只是 PC 端配合调试的软件,换成 Modbus Poll 即可。不再赘述。
|
||||
|
||||
## 注意事项
|
||||
|
||||
- 暂无
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 76 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 9.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.3 KiB |
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-06-21 flybreak first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "mb.h"
|
||||
#include "mb_m.h"
|
||||
|
||||
#ifdef PKG_MODBUS_MASTER_SAMPLE
|
||||
#define SLAVE_ADDR MB_SAMPLE_TEST_SLAVE_ADDR
|
||||
#define PORT_NUM MB_MASTER_USING_PORT_NUM
|
||||
#define PORT_BAUDRATE MB_MASTER_USING_PORT_BAUDRATE
|
||||
#else
|
||||
#define SLAVE_ADDR 0x01
|
||||
#define PORT_NUM 3
|
||||
#define PORT_BAUDRATE 115200
|
||||
#endif
|
||||
#define PORT_PARITY MB_PAR_EVEN
|
||||
|
||||
#define MB_POLL_THREAD_PRIORITY 10
|
||||
#define MB_SEND_THREAD_PRIORITY RT_THREAD_PRIORITY_MAX - 1
|
||||
|
||||
#define MB_SEND_REG_START 2
|
||||
#define MB_SEND_REG_NUM 2
|
||||
|
||||
#define MB_POLL_CYCLE_MS 500
|
||||
|
||||
static void send_thread_entry(void *parameter)
|
||||
{
|
||||
eMBMasterReqErrCode error_code = MB_MRE_NO_ERR;
|
||||
rt_uint16_t error_count = 0;
|
||||
USHORT data[MB_SEND_REG_NUM] = {0};
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Test Modbus Master */
|
||||
data[0] = (USHORT)(rt_tick_get() / 10);
|
||||
data[1] = (USHORT)(rt_tick_get() % 10);
|
||||
|
||||
error_code = eMBMasterReqWriteMultipleHoldingRegister(SLAVE_ADDR, /* salve address */
|
||||
MB_SEND_REG_START, /* register start address */
|
||||
MB_SEND_REG_NUM, /* register total number */
|
||||
data, /* data to be written */
|
||||
RT_WAITING_FOREVER); /* timeout */
|
||||
|
||||
/* Record the number of errors */
|
||||
if (error_code != MB_MRE_NO_ERR)
|
||||
{
|
||||
error_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void mb_master_poll(void *parameter)
|
||||
{
|
||||
eMBMasterInit(MB_RTU, 6, PORT_BAUDRATE, PORT_PARITY);
|
||||
eMBMasterEnable();
|
||||
|
||||
while (1)
|
||||
{
|
||||
eMBMasterPoll();
|
||||
rt_thread_mdelay(MB_POLL_CYCLE_MS);
|
||||
}
|
||||
}
|
||||
|
||||
static int mb_master_sample(int argc, char **argv)
|
||||
{
|
||||
static rt_uint8_t is_init = 0;
|
||||
rt_thread_t tid1 = RT_NULL, tid2 = RT_NULL;
|
||||
|
||||
if (is_init > 0)
|
||||
{
|
||||
rt_kprintf("sample is running\n");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
tid1 = rt_thread_create("md_m_poll", mb_master_poll, RT_NULL, 512, MB_POLL_THREAD_PRIORITY, 10);
|
||||
if (tid1 != RT_NULL)
|
||||
{
|
||||
rt_thread_startup(tid1);
|
||||
}
|
||||
else
|
||||
{
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
tid2 = rt_thread_create("md_m_send", send_thread_entry, RT_NULL, 512, MB_SEND_THREAD_PRIORITY - 2, 10);
|
||||
if (tid2 != RT_NULL)
|
||||
{
|
||||
rt_thread_startup(tid2);
|
||||
}
|
||||
else
|
||||
{
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
is_init = 1;
|
||||
return RT_EOK;
|
||||
|
||||
__exit:
|
||||
if (tid1)
|
||||
rt_thread_delete(tid1);
|
||||
if (tid2)
|
||||
rt_thread_delete(tid2);
|
||||
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
MSH_CMD_EXPORT(mb_master_sample, run a modbus master sample);
|
||||
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2022, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2019-06-21 flybreak first version
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "mb.h"
|
||||
#include "user_mb_app.h"
|
||||
|
||||
#ifdef PKG_MODBUS_SLAVE_SAMPLE
|
||||
#define SLAVE_ADDR MB_SAMPLE_SLAVE_ADDR
|
||||
#define PORT_NUM MB_SLAVE_USING_PORT_NUM
|
||||
#define PORT_BAUDRATE MB_SLAVE_USING_PORT_BAUDRATE
|
||||
#else
|
||||
#define SLAVE_ADDR 0x01
|
||||
#define PORT_NUM 2
|
||||
#define PORT_BAUDRATE 115200
|
||||
#endif
|
||||
|
||||
#define PORT_PARITY MB_PAR_EVEN
|
||||
|
||||
#define MB_POLL_THREAD_PRIORITY 10
|
||||
#define MB_SEND_THREAD_PRIORITY RT_THREAD_PRIORITY_MAX - 1
|
||||
|
||||
#define MB_POLL_CYCLE_MS 200
|
||||
|
||||
extern USHORT usSRegHoldBuf[S_REG_HOLDING_NREGS];
|
||||
|
||||
static void send_thread_entry(void *parameter)
|
||||
{
|
||||
USHORT *usRegHoldingBuf;
|
||||
usRegHoldingBuf = usSRegHoldBuf;
|
||||
rt_base_t level;
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Test Modbus Master */
|
||||
level = rt_hw_interrupt_disable();
|
||||
|
||||
usRegHoldingBuf[3] = (USHORT)(rt_tick_get() / 100);
|
||||
|
||||
rt_hw_interrupt_enable(level);
|
||||
|
||||
rt_thread_mdelay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
static void mb_slave_poll(void *parameter)
|
||||
{
|
||||
if (rt_strstr(parameter, "RTU"))
|
||||
{
|
||||
#ifdef PKG_MODBUS_SLAVE_RTU
|
||||
eMBInit(MB_RTU, SLAVE_ADDR, PORT_NUM, PORT_BAUDRATE, PORT_PARITY);
|
||||
#else
|
||||
rt_kprintf("Error: Please open RTU mode first");
|
||||
#endif
|
||||
}
|
||||
else if (rt_strstr(parameter, "ASCII"))
|
||||
{
|
||||
#ifdef PKG_MODBUS_SLAVE_ASCII
|
||||
eMBInit(MB_ASCII, SLAVE_ADDR, PORT_NUM, PORT_BAUDRATE, PORT_PARITY);
|
||||
#else
|
||||
rt_kprintf("Error: Please open ASCII mode first");
|
||||
#endif
|
||||
}
|
||||
else if (rt_strstr(parameter, "TCP"))
|
||||
{
|
||||
#ifdef PKG_MODBUS_SLAVE_TCP
|
||||
eMBTCPInit(0);
|
||||
#else
|
||||
rt_kprintf("Error: Please open TCP mode first");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_kprintf("Error: unknown parameter");
|
||||
}
|
||||
eMBEnable();
|
||||
while (1)
|
||||
{
|
||||
eMBPoll();
|
||||
rt_thread_mdelay(MB_POLL_CYCLE_MS);
|
||||
}
|
||||
}
|
||||
|
||||
static int mb_slave_sample(int argc, char **argv)
|
||||
{
|
||||
static rt_uint8_t is_init = 0;
|
||||
rt_thread_t tid1 = RT_NULL, tid2 = RT_NULL;
|
||||
|
||||
if (is_init > 0)
|
||||
{
|
||||
rt_kprintf("sample is running\n");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
if (argc < 2)
|
||||
{
|
||||
rt_kprintf("Usage: mb_slave_sample RTU/ASCII/TCP\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
tid1 = rt_thread_create("md_s_poll", mb_slave_poll, argv[1], 1024, MB_POLL_THREAD_PRIORITY, 10);
|
||||
if (tid1 != RT_NULL)
|
||||
{
|
||||
rt_thread_startup(tid1);
|
||||
}
|
||||
else
|
||||
{
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
tid2 = rt_thread_create("md_s_send", send_thread_entry, RT_NULL, 512, MB_SEND_THREAD_PRIORITY, 10);
|
||||
if (tid2 != RT_NULL)
|
||||
{
|
||||
rt_thread_startup(tid2);
|
||||
}
|
||||
else
|
||||
{
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
is_init = 1;
|
||||
return RT_EOK;
|
||||
|
||||
__exit:
|
||||
if (tid1)
|
||||
rt_thread_delete(tid1);
|
||||
if (tid2)
|
||||
rt_thread_delete(tid2);
|
||||
|
||||
return -RT_ERROR;
|
||||
}
|
||||
MSH_CMD_EXPORT(mb_slave_sample, run a modbus slave sample);
|
||||
Reference in New Issue
Block a user