view modbus

This commit is contained in:
hwq
2025-09-11 18:38:58 +08:00
parent 485e535c4d
commit ffe1456b3a
68 changed files with 6002 additions and 9079 deletions
+1 -30
View File
@@ -388,36 +388,7 @@ CONFIG_RT_LIBC_TZ_DEFAULT_SEC=0
# CONFIG_PKG_USING_KAWAII_MQTT is not set # CONFIG_PKG_USING_KAWAII_MQTT is not set
# CONFIG_PKG_USING_BC28_MQTT is not set # CONFIG_PKG_USING_BC28_MQTT is not set
# CONFIG_PKG_USING_WEBTERMINAL is not set # CONFIG_PKG_USING_WEBTERMINAL is not set
CONFIG_PKG_USING_FREEMODBUS=y # CONFIG_PKG_USING_FREEMODBUS is not set
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_NANOPB is not set # CONFIG_PKG_USING_NANOPB is not set
# CONFIG_PKG_USING_WIFI_HOST_DRIVER is not set # CONFIG_PKG_USING_WIFI_HOST_DRIVER is not set
# CONFIG_PKG_USING_ESP_HOSTED is not set # CONFIG_PKG_USING_ESP_HOSTED is not set
+16
View File
@@ -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')
+264
View File
@@ -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 @@
/* #ifndef __MB_H__
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU. #define __MB_H__
* 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
#include "port.h" #include <rtthread.h>
#include <assert.h>
//#include <inttypes.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #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 /*! \ingroup modbus
* \brief If register should be written or read. * \brief If register should be written or read.
@@ -100,8 +23,7 @@ extern "C" {
* \see eMBRegHoldingCB( ), eMBRegCoilsCB( ), eMBRegDiscreteCB( ) and * \see eMBRegHoldingCB( ), eMBRegCoilsCB( ), eMBRegDiscreteCB( ) and
* eMBRegInputCB( ). * eMBRegInputCB( ).
*/ */
typedef enum typedef enum {
{
MB_REG_READ, /*!< Read register values and pass to protocol stack. */ MB_REG_READ, /*!< Read register values and pass to protocol stack. */
MB_REG_WRITE /*!< Update register values. */ MB_REG_WRITE /*!< Update register values. */
} eMBRegisterMode; } eMBRegisterMode;
@@ -109,8 +31,7 @@ typedef enum
/*! \ingroup modbus /*! \ingroup modbus
* \brief Errorcodes used by all function in the protocol stack. * \brief Errorcodes used by all function in the protocol stack.
*/ */
typedef enum typedef enum {
{
MB_ENOERR, /*!< no error. */ MB_ENOERR, /*!< no error. */
MB_ENOREG, /*!< illegal register address. */ MB_ENOREG, /*!< illegal register address. */
MB_EINVAL, /*!< illegal argument. */ MB_EINVAL, /*!< illegal argument. */
@@ -121,8 +42,67 @@ typedef enum
MB_ETIMEDOUT /*!< timeout error occurred. */ MB_ETIMEDOUT /*!< timeout error occurred. */
} eMBErrorCode; } 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 /*! \ingroup modbus
* \brief Initialize the Modbus protocol stack. * \brief Initialize the Modbus protocol stack.
* *
@@ -148,24 +128,8 @@ typedef enum
* slave addresses are in the range 1 - 247. * slave addresses are in the range 1 - 247.
* - eMBErrorCode::MB_EPORTERR IF the porting layer returned an error. * - eMBErrorCode::MB_EPORTERR IF the porting layer returned an error.
*/ */
eMBErrorCode eMBInit( eMBMode eMode, UCHAR ucSlaveAddress, eMBErrorCode eMBInit(rt_uint8_t ucSlaveAddress, rt_uint8_t ucPort,
UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity ); rt_uint32_t ulBaudRate, eMBParity eParity );
/*! \ingroup modbus
* \brief Initialize the Modbus protocol stack for Modbus TCP.
*
* This function initializes the Modbus TCP Module. Please note that
* frame processing is still disabled until eMBEnable( ) is called.
*
* \param usTCPPort The TCP port to listen on.
* \return If the protocol stack has been initialized correctly the function
* returns eMBErrorCode::MB_ENOERR. Otherwise one of the following error
* codes is returned:
* - eMBErrorCode::MB_EINVAL If the slave address was not valid. Valid
* slave addresses are in the range 1 - 247.
* - eMBErrorCode::MB_EPORTERR IF the porting layer returned an error.
*/
eMBErrorCode eMBTCPInit( USHORT usTCPPort );
/*! \ingroup modbus /*! \ingroup modbus
* \brief Release resources used by the protocol stack. * \brief Release resources used by the protocol stack.
@@ -238,9 +202,8 @@ eMBErrorCode eMBPoll( void );
* mbconfig.h is to small it returns eMBErrorCode::MB_ENORES. Otherwise * mbconfig.h is to small it returns eMBErrorCode::MB_ENORES. Otherwise
* it returns eMBErrorCode::MB_ENOERR. * it returns eMBErrorCode::MB_ENOERR.
*/ */
eMBErrorCode eMBSetSlaveID( UCHAR ucSlaveID, BOOL xIsRunning, eMBErrorCode eMBSetSlaveID( rt_uint8_t ucSlaveID, rt_uint8_t xIsRunning,
UCHAR const *pucAdditional, rt_uint8_t const *pucAdditional, rt_uint16_t usAdditionalLen );
USHORT usAdditionalLen );
/*! \ingroup modbus /*! \ingroup modbus
* \brief Registers a callback handler for a given function code. * \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 * case the values in mbconfig.h should be adjusted. If the argument was not
* valid it returns eMBErrorCode::MB_EINVAL. * valid it returns eMBErrorCode::MB_EINVAL.
*/ */
eMBErrorCode eMBRegisterCB( UCHAR ucFunctionCode, eMBErrorCode eMBRegisterCB( rt_uint8_t ucFunctionCode, pxMBFunctionHandler pxHandler );
pxMBFunctionHandler pxHandler );
/* ----------------------- Callback -----------------------------------------*/ /* ----------------------- Callback -----------------------------------------*/
@@ -309,8 +271,8 @@ eMBErrorCode eMBRegisterCB( UCHAR ucFunctionCode,
* - eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case * - eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case
* a <b>SLAVE DEVICE FAILURE</b> exception is sent as a response. * a <b>SLAVE DEVICE FAILURE</b> exception is sent as a response.
*/ */
eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, eMBErrorCode eMBRegInputCB( rt_uint8_t * pucRegBuffer, rt_uint16_t usAddress,
USHORT usNRegs ); rt_uint16_t usNRegs );
/*! \ingroup modbus_registers /*! \ingroup modbus_registers
* \brief Callback function used if a <em>Holding Register</em> value is * \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 * - eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case
* a <b>SLAVE DEVICE FAILURE</b> exception is sent as a response. * a <b>SLAVE DEVICE FAILURE</b> exception is sent as a response.
*/ */
eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, eMBErrorCode eMBRegHoldingCB( rt_uint8_t * pucRegBuffer, rt_uint16_t usAddress,
USHORT usNRegs, eMBRegisterMode eMode ); rt_uint16_t usNRegs, eMBRegisterMode eMode );
/*! \ingroup modbus_registers /*! \ingroup modbus_registers
* \brief Callback function used if a <em>Coil Register</em> value is * \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 * - eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case
* a <b>SLAVE DEVICE FAILURE</b> exception is sent as a response. * a <b>SLAVE DEVICE FAILURE</b> exception is sent as a response.
*/ */
eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, eMBErrorCode eMBRegCoilsCB( rt_uint8_t * pucRegBuffer, rt_uint16_t usAddress,
USHORT usNCoils, eMBRegisterMode eMode ); rt_uint16_t usNCoils, eMBRegisterMode eMode );
/*! \ingroup modbus_registers /*! \ingroup modbus_registers
* \brief Callback function used if a <em>Input Discrete Register</em> value is * \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 * - eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case
* a <b>SLAVE DEVICE FAILURE</b> exception is sent as a response. * a <b>SLAVE DEVICE FAILURE</b> exception is sent as a response.
*/ */
eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, eMBErrorCode eMBRegDiscreteCB( rt_uint8_t * pucRegBuffer, rt_uint16_t usAddress,
USHORT usNDiscrete ); 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 #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 <rtthread.h>
#include "port.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, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
@@ -56,7 +26,7 @@ static const UCHAR aucCRCHi[] = {
0x00, 0xC1, 0x81, 0x40 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, 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,
0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9,
@@ -81,18 +51,20 @@ static const UCHAR aucCRCLo[] = {
0x41, 0x81, 0x80, 0x40 0x41, 0x81, 0x80, 0x40
}; };
USHORT rt_uint16_t usMBCRC16( rt_uint8_t * pucFrame, rt_uint16_t usLen )
usMBCRC16( UCHAR * pucFrame, USHORT usLen )
{ {
UCHAR ucCRCHi = 0xFF; rt_uint8_t ucCRCHi = 0xFF;
UCHAR ucCRCLo = 0xFF; rt_uint8_t ucCRCLo = 0xFF;
int iIndex; int iIndex;
while( usLen-- ) while( usLen-- )
{ {
iIndex = ucCRCLo ^ *( pucFrame++ ); iIndex = ucCRCLo ^ *( pucFrame++ );
ucCRCLo = ( UCHAR )( ucCRCHi ^ aucCRCHi[iIndex] ); ucCRCLo = ( rt_uint8_t )( ucCRCHi ^ aucCRCHi[iIndex] );
ucCRCHi = aucCRCLo[iIndex]; ucCRCHi = aucCRCLo[iIndex];
} }
return ( USHORT )( ucCRCHi << 8 | ucCRCLo ); return ( rt_uint16_t )( ucCRCHi << 8 | ucCRCLo );
} }
+9
View File
@@ -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
+46
View File
@@ -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;
}
+41
View File
@@ -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
@@ -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 "stdlib.h" #include <string.h>
#include "string.h"
/* ----------------------- Platform includes --------------------------------*/ #include <rtthread.h>
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h" #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_ADDR_OFF ( MB_PDU_DATA_OFF )
#define MB_PDU_FUNC_READ_COILCNT_OFF ( MB_PDU_DATA_OFF + 2 ) #define MB_PDU_FUNC_READ_COILCNT_OFF ( MB_PDU_DATA_OFF + 2 )
#define MB_PDU_FUNC_READ_SIZE ( 4 ) #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_SIZE_MIN ( 5 )
#define MB_PDU_FUNC_WRITE_MUL_COILCNT_MAX ( 0x07B0 ) #define MB_PDU_FUNC_WRITE_MUL_COILCNT_MAX ( 0x07B0 )
/* ----------------------- Static functions ---------------------------------*/
eMBException prveMBError2Exception( eMBErrorCode eErrorCode ); eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
/* ----------------------- Start implementation -----------------------------*/ eMBException eMBFuncReadCoils( rt_uint8_t * pucFrame, rt_uint16_t * usLen )
#if MB_FUNC_READ_COILS_ENABLED > 0
eMBException
eMBFuncReadCoils( UCHAR * pucFrame, USHORT * usLen )
{ {
USHORT usRegAddress; rt_uint16_t usRegAddress;
USHORT usCoilCount; rt_uint16_t usCoilCount;
UCHAR ucNBytes; rt_uint8_t ucNBytes;
UCHAR *pucFrameCur; rt_uint8_t *pucFrameCur;
eMBException eStatus = MB_EX_NONE; eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus; eMBErrorCode eRegStatus;
if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) ) if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
{ {
usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 ); usRegAddress = ( rt_uint16_t )( 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 + 1] );
usRegAddress++; usRegAddress++;
usCoilCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_COILCNT_OFF] << 8 ); usCoilCount = ( rt_uint16_t )( 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 + 1] );
/* Check if the number of registers to read is valid. If not /* Check if the number of registers to read is valid. If not
* return Modbus illegal data value exception. * 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. */ * byte is only partially field with unused coils set to zero. */
if( ( usCoilCount & 0x0007 ) != 0 ) if( ( usCoilCount & 0x0007 ) != 0 )
{ {
ucNBytes = ( UCHAR )( usCoilCount / 8 + 1 ); ucNBytes = ( rt_uint8_t )( usCoilCount / 8 + 1 );
} }
else else
{ {
ucNBytes = ( UCHAR )( usCoilCount / 8 ); ucNBytes = ( rt_uint8_t )( usCoilCount / 8 );
} }
*pucFrameCur++ = ucNBytes; *pucFrameCur++ = ucNBytes;
*usLen += 1; *usLen += 1;
@@ -142,22 +100,19 @@ eMBFuncReadCoils( UCHAR * pucFrame, USHORT * usLen )
} }
return eStatus; return eStatus;
} }
#endif
#if MB_FUNC_WRITE_COIL_ENABLED > 0 eMBException eMBFuncWriteCoil( rt_uint8_t * pucFrame, rt_uint16_t * usLen )
eMBException
eMBFuncWriteCoil( UCHAR * pucFrame, USHORT * usLen )
{ {
USHORT usRegAddress; rt_uint16_t usRegAddress;
UCHAR ucBuf[2]; rt_uint8_t ucBuf[2];
eMBException eStatus = MB_EX_NONE; eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus; eMBErrorCode eRegStatus;
if( *usLen == ( MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN ) ) if( *usLen == ( MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN ) )
{ {
usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF] << 8 ); usRegAddress = ( rt_uint16_t )( 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 + 1] );
usRegAddress++; usRegAddress++;
if( ( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF + 1] == 0x00 ) && if( ( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF + 1] == 0x00 ) &&
@@ -196,39 +151,36 @@ eMBFuncWriteCoil( UCHAR * pucFrame, USHORT * usLen )
return eStatus; return eStatus;
} }
#endif
#if MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED > 0 eMBException eMBFuncWriteMultipleCoils( rt_uint8_t * pucFrame, rt_uint16_t * usLen )
eMBException
eMBFuncWriteMultipleCoils( UCHAR * pucFrame, USHORT * usLen )
{ {
USHORT usRegAddress; rt_uint16_t usRegAddress;
USHORT usCoilCnt; rt_uint16_t usCoilCnt;
UCHAR ucByteCount; rt_uint8_t ucByteCount;
UCHAR ucByteCountVerify; rt_uint8_t ucByteCountVerify;
eMBException eStatus = MB_EX_NONE; eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus; eMBErrorCode eRegStatus;
if( *usLen > ( MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN ) ) if( *usLen > ( MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN ) )
{ {
usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF] << 8 ); usRegAddress = ( rt_uint16_t )( 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 + 1] );
usRegAddress++; usRegAddress++;
usCoilCnt = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF] << 8 ); usCoilCnt = ( rt_uint16_t )( 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 + 1] );
ucByteCount = pucFrame[MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF]; ucByteCount = pucFrame[MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF];
/* Compute the number of expected bytes in the request. */ /* Compute the number of expected bytes in the request. */
if( ( usCoilCnt & 0x0007 ) != 0 ) if( ( usCoilCnt & 0x0007 ) != 0 )
{ {
ucByteCountVerify = ( UCHAR )( usCoilCnt / 8 + 1 ); ucByteCountVerify = ( rt_uint8_t )( usCoilCnt / 8 + 1 );
} }
else else
{ {
ucByteCountVerify = ( UCHAR )( usCoilCnt / 8 ); ucByteCountVerify = ( rt_uint8_t )( usCoilCnt / 8 );
} }
if( ( usCoilCnt >= 1 ) && if( ( usCoilCnt >= 1 ) &&
@@ -266,4 +218,4 @@ eMBFuncWriteMultipleCoils( UCHAR * pucFrame, USHORT * usLen )
return eStatus; return eStatus;
} }
#endif
+92
View File
@@ -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;
}
@@ -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 "stdlib.h" #include <string.h>
#include "string.h"
/* ----------------------- Platform includes --------------------------------*/ #include <rtthread.h>
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h" #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_ADDR_OFF ( MB_PDU_DATA_OFF + 0)
#define MB_PDU_FUNC_READ_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 ) #define MB_PDU_FUNC_READ_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 )
#define MB_PDU_FUNC_READ_SIZE ( 4 ) #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_WRITE_VALUES_OFF ( MB_PDU_DATA_OFF + 9 )
#define MB_PDU_FUNC_READWRITE_SIZE_MIN ( 9 ) #define MB_PDU_FUNC_READWRITE_SIZE_MIN ( 9 )
/* ----------------------- Static functions ---------------------------------*/
eMBException prveMBError2Exception( eMBErrorCode eErrorCode ); eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
/* ----------------------- Start implementation -----------------------------*/ eMBException eMBFuncWriteHoldingRegister( rt_uint8_t * pucFrame, rt_uint16_t * usLen )
#if MB_FUNC_WRITE_HOLDING_ENABLED > 0
eMBException
eMBFuncWriteHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
{ {
USHORT usRegAddress; rt_uint16_t usRegAddress;
eMBException eStatus = MB_EX_NONE; eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus; eMBErrorCode eRegStatus;
if( *usLen == ( MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN ) ) if( *usLen == ( MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN ) )
{ {
usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF] << 8 ); usRegAddress = ( rt_uint16_t )( 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 + 1] );
usRegAddress++; usRegAddress++;
/* Make callback to update the value. */ /* Make callback to update the value. */
@@ -103,33 +62,30 @@ eMBFuncWriteHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
} }
return eStatus; return eStatus;
} }
#endif
#if MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED > 0 eMBException eMBFuncWriteMultipleHoldingRegister( rt_uint8_t * pucFrame, rt_uint16_t * usLen )
eMBException
eMBFuncWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
{ {
USHORT usRegAddress; rt_uint16_t usRegAddress;
USHORT usRegCount; rt_uint16_t usRegCount;
UCHAR ucRegByteCount; rt_uint8_t ucRegByteCount;
eMBException eStatus = MB_EX_NONE; eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus; eMBErrorCode eRegStatus;
if( *usLen >= ( MB_PDU_FUNC_WRITE_MUL_SIZE_MIN + MB_PDU_SIZE_MIN ) ) 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 = ( rt_uint16_t )( 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 + 1] );
usRegAddress++; usRegAddress++;
usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF] << 8 ); usRegCount = ( rt_uint16_t )( 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 + 1] );
ucRegByteCount = pucFrame[MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF]; ucRegByteCount = pucFrame[MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF];
if( ( usRegCount >= 1 ) && if( ( usRegCount >= 1 ) &&
( usRegCount <= MB_PDU_FUNC_WRITE_MUL_REGCNT_MAX ) && ( 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. */ /* Make callback to update the register values. */
eRegStatus = eRegStatus =
@@ -162,28 +118,24 @@ eMBFuncWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
} }
return eStatus; return eStatus;
} }
#endif
#if MB_FUNC_READ_HOLDING_ENABLED > 0 eMBException eMBFuncReadHoldingRegister( rt_uint8_t * pucFrame, rt_uint16_t * usLen )
eMBException
eMBFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
{ {
USHORT usRegAddress; rt_uint16_t usRegAddress;
USHORT usRegCount; rt_uint16_t usRegCount;
UCHAR *pucFrameCur; rt_uint8_t *pucFrameCur;
eMBException eStatus = MB_EX_NONE; eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus; eMBErrorCode eRegStatus;
if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) ) if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
{ {
usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 ); usRegAddress = ( rt_uint16_t )( 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 + 1] );
usRegAddress++; usRegAddress++;
usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] << 8 ); usRegCount = ( rt_uint16_t )( 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 + 1] );
/* Check if the number of registers to read is valid. If not /* Check if the number of registers to read is valid. If not
* return Modbus illegal data value exception. * return Modbus illegal data value exception.
@@ -199,7 +151,7 @@ eMBFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
*usLen += 1; *usLen += 1;
/* Second byte in the response contain the number of bytes. */ /* Second byte in the response contain the number of bytes. */
*pucFrameCur++ = ( UCHAR ) ( usRegCount * 2 ); *pucFrameCur++ = ( rt_uint8_t ) ( usRegCount * 2 );
*usLen += 1; *usLen += 1;
/* Make callback to fill the buffer. */ /* Make callback to fill the buffer. */
@@ -227,38 +179,34 @@ eMBFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
return eStatus; return eStatus;
} }
#endif
#if MB_FUNC_READWRITE_HOLDING_ENABLED > 0 eMBException eMBFuncReadWriteMultipleHoldingRegister( rt_uint8_t * pucFrame, rt_uint16_t * usLen )
eMBException
eMBFuncReadWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
{ {
USHORT usRegReadAddress; rt_uint16_t usRegReadAddress;
USHORT usRegReadCount; rt_uint16_t usRegReadCount;
USHORT usRegWriteAddress; rt_uint16_t usRegWriteAddress;
USHORT usRegWriteCount; rt_uint16_t usRegWriteCount;
UCHAR ucRegWriteByteCount; rt_uint8_t ucRegWriteByteCount;
UCHAR *pucFrameCur; rt_uint8_t *pucFrameCur;
eMBException eStatus = MB_EX_NONE; eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus; eMBErrorCode eRegStatus;
if( *usLen >= ( MB_PDU_FUNC_READWRITE_SIZE_MIN + MB_PDU_SIZE_MIN ) ) if( *usLen >= ( MB_PDU_FUNC_READWRITE_SIZE_MIN + MB_PDU_SIZE_MIN ) )
{ {
usRegReadAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_READ_ADDR_OFF] << 8U ); usRegReadAddress = ( rt_uint16_t )( 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 + 1] );
usRegReadAddress++; usRegReadAddress++;
usRegReadCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_READ_REGCNT_OFF] << 8U ); usRegReadCount = ( rt_uint16_t )( 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 + 1] );
usRegWriteAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_ADDR_OFF] << 8U ); usRegWriteAddress = ( rt_uint16_t )( 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 + 1] );
usRegWriteAddress++; usRegWriteAddress++;
usRegWriteCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_REGCNT_OFF] << 8U ); usRegWriteCount = ( rt_uint16_t )( 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 + 1] );
ucRegWriteByteCount = pucFrame[MB_PDU_FUNC_READWRITE_BYTECNT_OFF]; ucRegWriteByteCount = pucFrame[MB_PDU_FUNC_READWRITE_BYTECNT_OFF];
@@ -281,7 +229,7 @@ eMBFuncReadWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
*usLen += 1; *usLen += 1;
/* Second byte in the response contain the number of bytes. */ /* Second byte in the response contain the number of bytes. */
*pucFrameCur++ = ( UCHAR ) ( usRegReadCount * 2 ); *pucFrameCur++ = ( rt_uint8_t ) ( usRegReadCount * 2 );
*usLen += 1; *usLen += 1;
/* Make the read callback. */ /* Make the read callback. */
@@ -305,4 +253,5 @@ eMBFuncReadWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
return eStatus; return eStatus;
} }
#endif
+83
View File
@@ -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;
}
+51
View File
@@ -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;
}
+26
View File
@@ -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);
}
+84
View File
@@ -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 "stdlib.h"
#include "string.h" #include "string.h"
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h" #include "mb.h"
#include "mbrtu.h" #include "mbrtu.h"
#include "mbframe.h"
#include "mbcrc.h" #include "mbcrc.h"
#include "mbport.h" #include "mbport.h"
/* ----------------------- Defines ------------------------------------------*/
#define MB_SER_PDU_SIZE_MIN 4 /*!< Minimum size of a Modbus RTU frame. */ #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_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_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_ADDR_OFF 0 /*!< Offset of slave address in Ser-PDU. */
#define MB_SER_PDU_PDU_OFF 1 /*!< Offset of Modbus-PDU 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_INIT, /*!< Receiver is in initial state. */
STATE_RX_IDLE, /*!< Receiver is in idle state. */ STATE_RX_IDLE, /*!< Receiver is in idle state. */
STATE_RX_RCV, /*!< Frame is beeing received. */ STATE_RX_RCV, /*!< Frame is beeing received. */
STATE_RX_ERROR /*!< If the frame is invalid. */ STATE_RX_ERROR /*!< If the frame is invalid. */
} eMBRcvState; } eMBRcvState;
typedef enum typedef enum {
{
STATE_TX_IDLE, /*!< Transmitter is in idle state. */ STATE_TX_IDLE, /*!< Transmitter is in idle state. */
STATE_TX_XMIT /*!< Transmitter is in transfer state. */ STATE_TX_XMIT /*!< Transmitter is in transfer state. */
} eMBSndState; } eMBSndState;
/* ----------------------- Static variables ---------------------------------*/
static volatile eMBSndState eSndState; static volatile eMBSndState eSndState;
static volatile eMBRcvState eRcvState; 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 rt_uint8_t *pucSndBufferCur;
static volatile USHORT usSndBufferCount; static volatile rt_uint16_t usSndBufferCount;
static volatile USHORT usRcvBufferPos; static volatile rt_uint16_t usRcvBufferPos;
/* ----------------------- Start implementation -----------------------------*/ eMBErrorCode eMBRTUInit( rt_uint8_t ucSlaveAddress, rt_uint8_t ucPort,
eMBErrorCode rt_uint32_t ulBaudRate, eMBParity eParity )
eMBRTUInit( UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity )
{ {
eMBErrorCode eStatus = MB_ENOERR; eMBErrorCode eStatus = MB_ENOERR;
ULONG usTimerT35_50us; rt_uint32_t usTimerT35_50us;
( void )ucSlaveAddress; ( void )ucSlaveAddress;
ENTER_CRITICAL_SECTION( ); EnterCriticalSection();
/* Modbus RTU uses 8 Databits. */ /* Modbus RTU uses 8 Databits. */
/* If baudrate > 19200 then we should use the fixed timer values /* 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 ); usTimerT35_50us = ( 7UL * 220000UL ) / ( 2UL * ulBaudRate );
} }
if( xMBPortTimersInit( ( USHORT ) usTimerT35_50us ) != TRUE ) if( xMBPortTimersInit( ( rt_uint16_t ) usTimerT35_50us ) != TRUE )
{ {
eStatus = MB_EPORTERR; eStatus = MB_EPORTERR;
} }
@@ -115,15 +74,14 @@ eMBRTUInit( UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity ePar
{ {
eStatus = MB_EPORTERR; eStatus = MB_EPORTERR;
} }
EXIT_CRITICAL_SECTION( ); ExitCriticalSection();
return eStatus; return eStatus;
} }
void void eMBRTUStart( void )
eMBRTUStart( void )
{ {
ENTER_CRITICAL_SECTION( ); EnterCriticalSection();
/* Initially the receiver is in the state STATE_RX_INIT. we start /* 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 * 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 * to STATE_RX_IDLE. This makes sure that we delay startup of the
@@ -131,31 +89,29 @@ eMBRTUStart( void )
*/ */
eRcvState = STATE_RX_INIT; eRcvState = STATE_RX_INIT;
vMBPortSerialEnable( TRUE, FALSE ); vMBPortSerialEnable( TRUE, FALSE );
vMBPortTimersEnable( ); vMBPortTimersEnable();
EXIT_CRITICAL_SECTION( ); ExitCriticalSection();
} }
void void eMBRTUStop( void )
eMBRTUStop( void )
{ {
ENTER_CRITICAL_SECTION( ); EnterCriticalSection();
vMBPortSerialEnable( FALSE, FALSE ); vMBPortSerialEnable( FALSE, FALSE );
vMBPortTimersDisable( ); vMBPortTimersDisable();
EXIT_CRITICAL_SECTION( ); ExitCriticalSection();
} }
eMBErrorCode eMBErrorCode eMBRTUReceive( rt_uint8_t * pucRcvAddress, rt_uint8_t ** pucFrame, rt_uint16_t * pusLength )
eMBRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength )
{ {
eMBErrorCode eStatus = MB_ENOERR; eMBErrorCode eStatus = MB_ENOERR;
ENTER_CRITICAL_SECTION( ); EnterCriticalSection();
RT_ASSERT( usRcvBufferPos <= MB_SER_PDU_SIZE_MAX ); RT_ASSERT( usRcvBufferPos <= MB_SER_PDU_SIZE_MAX );
/* Length and CRC check */ /* Length and CRC check */
if( ( usRcvBufferPos >= MB_SER_PDU_SIZE_MIN ) 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 /* Save the address field. All frames are passed to the upper layed
* and the decision if a frame is used is done there. * 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 /* Total length of Modbus-PDU is Modbus-Serial-Line-PDU minus
* size of address field and CRC checksum. * 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. */ /* 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 else
{ {
eStatus = MB_EIO; eStatus = MB_EIO;
} }
EXIT_CRITICAL_SECTION( ); ExitCriticalSection();
return eStatus; return eStatus;
} }
eMBErrorCode eMBErrorCode eMBRTUSend( rt_uint8_t ucSlaveAddress, const rt_uint8_t * pucFrame, rt_uint16_t usLength )
eMBRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength )
{ {
eMBErrorCode eStatus = MB_ENOERR; 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 /* 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 * 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 ) if( eRcvState == STATE_RX_IDLE )
{ {
/* First byte before the Modbus-PDU is the slave address. */ /* First byte before the Modbus-PDU is the slave address. */
pucSndBufferCur = ( UCHAR * ) pucFrame - 1; pucSndBufferCur = ( rt_uint8_t * ) pucFrame - 1;
usSndBufferCount = 1; usSndBufferCount = 1;
/* Now copy the Modbus-PDU into the Modbus-Serial-Line-PDU. */ /* 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; usSndBufferCount += usLength;
/* Calculate CRC16 checksum for Modbus-Serial-Line-PDU. */ /* Calculate CRC16 checksum for Modbus-Serial-Line-PDU. */
usCRC16 = usMBCRC16( ( UCHAR * ) pucSndBufferCur, usSndBufferCount ); usCRC16 = usMBCRC16( ( rt_uint8_t * ) pucSndBufferCur, usSndBufferCount );
ucRTUBuf[usSndBufferCount++] = ( UCHAR )( usCRC16 & 0xFF ); ucRTUBuf[usSndBufferCount++] = ( rt_uint8_t )( usCRC16 & 0xFF );
ucRTUBuf[usSndBufferCount++] = ( UCHAR )( usCRC16 >> 8 ); ucRTUBuf[usSndBufferCount++] = ( rt_uint8_t )( usCRC16 >> 8 );
/* Activate the transmitter. */ /* Activate the transmitter. */
eSndState = STATE_TX_XMIT; eSndState = STATE_TX_XMIT;
@@ -214,20 +170,21 @@ eMBRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength )
{ {
eStatus = MB_EIO; eStatus = MB_EIO;
} }
EXIT_CRITICAL_SECTION( );
ExitCriticalSection();
return eStatus; return eStatus;
} }
BOOL rt_uint8_t xMBRTUReceiveFSM( void )
xMBRTUReceiveFSM( void )
{ {
BOOL xTaskNeedSwitch = FALSE; rt_uint8_t xTaskNeedSwitch = FALSE;
UCHAR ucByte; rt_uint8_t ucByte;
RT_ASSERT( eSndState == STATE_TX_IDLE ); RT_ASSERT( eSndState == STATE_TX_IDLE );
/* Always read the character. */ /* Always read the character. */
( void )xMBPortSerialGetByte( ( CHAR * ) & ucByte ); ( void )xMBPortSerialGetByte((char *) &ucByte);
switch ( eRcvState ) switch ( eRcvState )
{ {
@@ -235,14 +192,14 @@ xMBRTUReceiveFSM( void )
* wait until the frame is finished. * wait until the frame is finished.
*/ */
case STATE_RX_INIT: case STATE_RX_INIT:
vMBPortTimersEnable( ); vMBPortTimersEnable();
break; break;
/* In the error state we wait until all characters in the /* In the error state we wait until all characters in the
* damaged frame are transmitted. * damaged frame are transmitted.
*/ */
case STATE_RX_ERROR: case STATE_RX_ERROR:
vMBPortTimersEnable( ); vMBPortTimersEnable();
break; break;
/* In the idle state we wait for a new character. If a character /* In the idle state we wait for a new character. If a character
@@ -255,7 +212,7 @@ xMBRTUReceiveFSM( void )
eRcvState = STATE_RX_RCV; eRcvState = STATE_RX_RCV;
/* Enable t3.5 timers. */ /* Enable t3.5 timers. */
vMBPortTimersEnable( ); vMBPortTimersEnable();
break; break;
/* We are currently receiving a frame. Reset the timer after /* We are currently receiving a frame. Reset the timer after
@@ -278,10 +235,9 @@ xMBRTUReceiveFSM( void )
return xTaskNeedSwitch; return xTaskNeedSwitch;
} }
BOOL rt_uint8_t xMBRTUTransmitFSM( void )
xMBRTUTransmitFSM( void )
{ {
BOOL xNeedPoll = FALSE; rt_uint8_t xNeedPoll = FALSE;
RT_ASSERT( eRcvState == STATE_RX_IDLE ); RT_ASSERT( eRcvState == STATE_RX_IDLE );
@@ -298,7 +254,7 @@ xMBRTUTransmitFSM( void )
/* check if we are finished. */ /* check if we are finished. */
if( usSndBufferCount != 0 ) if( usSndBufferCount != 0 )
{ {
xMBPortSerialPutByte( ( CHAR )*pucSndBufferCur ); xMBPortSerialPutByte((char)*pucSndBufferCur );
pucSndBufferCur++; /* next byte in sendbuffer. */ pucSndBufferCur++; /* next byte in sendbuffer. */
usSndBufferCount--; usSndBufferCount--;
} }
@@ -316,10 +272,9 @@ xMBRTUTransmitFSM( void )
return xNeedPoll; return xNeedPoll;
} }
BOOL rt_uint8_t xMBRTUTimerT35Expired( void )
xMBRTUTimerT35Expired( void )
{ {
BOOL xNeedPoll = FALSE; rt_uint8_t xNeedPoll = FALSE;
switch ( eRcvState ) switch ( eRcvState )
{ {
@@ -345,8 +300,11 @@ xMBRTUTimerT35Expired( void )
break; break;
} }
vMBPortTimersDisable( ); vMBPortTimersDisable();
eRcvState = STATE_RX_IDLE; eRcvState = STATE_RX_IDLE;
return xNeedPoll; return xNeedPoll;
} }
+31
View File
@@ -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 "mb.h"
#include "mbport.h" #include "mbport.h"
#include "rtdevice.h"
#include "board.h"
/* ----------------------- Static variables ---------------------------------*/
/* software simulation serial transmit IRQ handler thread stack */ /* software simulation serial transmit IRQ handler thread stack */
#ifdef rt_align //rt_align(RT_ALIGN_SIZE)
rt_align(RT_ALIGN_SIZE)
#else
ALIGN(RT_ALIGN_SIZE)
#endif
static rt_uint8_t serial_soft_trans_irq_stack[512]; static rt_uint8_t serial_soft_trans_irq_stack[512];
/* software simulation serial transmit IRQ handler thread */ /* software simulation serial transmit IRQ handler thread */
static struct rt_thread thread_serial_soft_trans_irq; static struct rt_thread thread_serial_soft_trans_irq;
/* serial event */ /* serial event */
static struct rt_event event_serial; static struct rt_event event_serial;
/* modbus slave serial device */ /* modbus slave serial device */
static struct rt_serial_device *serial; static struct rt_serial_device *serial;
/* ----------------------- Defines ------------------------------------------*/
/* serial transmit event */ /* serial transmit event */
#define EVENT_SERIAL_TRANS_START (1<<0) #define EVENT_SERIAL_TRANS_START (1<<0)
/* ----------------------- static functions ---------------------------------*/
static void prvvUARTTxReadyISR(void); static void prvvUARTTxReadyISR(void);
static void prvvUARTRxISR(void); static void prvvUARTRxISR(void);
static rt_err_t serial_rx_ind(rt_device_t dev, rt_size_t size); static rt_err_t serial_rx_ind(rt_device_t dev, rt_size_t size);
static void serial_soft_trans_irq(void* parameter); static void serial_soft_trans_irq(void* parameter);
/* ----------------------- Start implementation -----------------------------*/ rt_uint8_t xMBPortSerialInit(rt_uint8_t ucPORT, rt_uint32_t ulBaudRate,
BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, rt_uint8_t ucDataBits, eMBParity eParity)
eMBParity eParity)
{ {
rt_device_t dev = RT_NULL; rt_device_t dev = RT_NULL;
char uart_name[20]; char uart_name[20];
@@ -123,7 +98,7 @@ BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
return TRUE; return TRUE;
} }
void vMBPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable) void vMBPortSerialEnable(rt_uint8_t xRxEnable, rt_uint8_t xTxEnable)
{ {
rt_uint32_t recved_event; rt_uint32_t recved_event;
if (xRxEnable) if (xRxEnable)
@@ -163,13 +138,13 @@ void vMBPortClose(void)
serial->parent.close(&(serial->parent)); serial->parent.close(&(serial->parent));
} }
BOOL xMBPortSerialPutByte(CHAR ucByte) rt_uint8_t xMBPortSerialPutByte(char ucByte)
{ {
serial->parent.write(&(serial->parent), 0, &ucByte, 1); serial->parent.write(&(serial->parent), 0, &ucByte, 1);
return TRUE; return TRUE;
} }
BOOL xMBPortSerialGetByte(CHAR * pucByte) rt_uint8_t xMBPortSerialGetByte(char * pucByte)
{ {
serial->parent.read(&(serial->parent), 0, pucByte, 1); serial->parent.read(&(serial->parent), 0, pucByte, 1);
return TRUE; return TRUE;
@@ -228,3 +203,6 @@ static rt_err_t serial_rx_ind(rt_device_t dev, rt_size_t size) {
prvvUARTRxISR(); prvvUARTRxISR();
return RT_EOK; return RT_EOK;
} }
+41
View File
@@ -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;
}
+104
View File
@@ -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 #ifndef __MB_UTILS_H__
#define _MB_UTILS_H #define __MB_UTILS_H__
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -75,8 +46,8 @@ extern "C" {
* xMBUtilSetBits( ucBits, 8, 8, 0x5A); * xMBUtilSetBits( ucBits, 8, 8, 0x5A);
* \endcode * \endcode
*/ */
void xMBUtilSetBits( UCHAR * ucByteBuf, USHORT usBitOffset, void xMBUtilSetBits( rt_uint8_t * ucByteBuf, rt_uint16_t usBitOffset,
UCHAR ucNBits, UCHAR ucValues ); rt_uint8_t ucNBits, rt_uint8_t ucValues );
/*! \brief Function to read bits in a byte buffer. /*! \brief Function to read bits in a byte buffer.
* *
@@ -90,21 +61,21 @@ void xMBUtilSetBits( UCHAR * ucByteBuf, USHORT usBitOffset,
* than 8. * than 8.
* *
* \code * \code
* UCHAR ucBits[2] = {0, 0}; * rt_uint8_t ucBits[2] = {0, 0};
* UCHAR ucResult; * rt_uint8_t ucResult;
* *
* // Extract the bits 3 - 10. * // Extract the bits 3 - 10.
* ucResult = xMBUtilGetBits( ucBits, 3, 8 ); * ucResult = xMBUtilGetBits( ucBits, 3, 8 );
* \endcode * \endcode
*/ */
UCHAR xMBUtilGetBits( UCHAR * ucByteBuf, USHORT usBitOffset, rt_uint8_t xMBUtilGetBits( rt_uint8_t * ucByteBuf, rt_uint16_t usBitOffset, rt_uint8_t ucNBits );
UCHAR ucNBits );
/*! @} */ /*! @} */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif #endif
+4 -2
View File
@@ -2,13 +2,15 @@
#include <rtthread.h> #include <rtthread.h>
#include "mb.h" #include "mb.h"
#include "chrg_mb.h"
#include "chrg_comm.h" #include "chrg_comm.h"
#define LOG_TAG "chrg.comm" #define LOG_TAG "chrg.comm"
#define DBG_LEVEL DBG_LOG #define DBG_LEVEL DBG_LOG
#include <rtdbg.h> #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 = { struct chrg_comm_t chrgcomm = {
.tid_poll = RT_NULL, .tid_poll = RT_NULL,
@@ -49,7 +51,7 @@ static void chrg_comm_poll (void *pdata)
return ; return ;
} }
eMBInit(MB_RTU, pCOMM->addr, 1, 115200, MB_PAR_EVEN); eMBInit(pCOMM->addr, 1, 115200, MB_PAR_EVEN);
eMBEnable(); 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 //Slave mode:DiscreteInputs variables
USHORT usSDiscInStart = S_DISCRETE_INPUT_START; rt_uint16_t usSDiscInStart = S_DISCRETE_INPUT_START;
#if S_DISCRETE_INPUT_NDISCRETES%8 rt_uint8_t ucSDiscInBuf[(S_DISCRETE_INPUT_NDISCRETES+7)/8];
UCHAR ucSDiscInBuf[S_DISCRETE_INPUT_NDISCRETES/8+1];
#else
UCHAR ucSDiscInBuf[S_DISCRETE_INPUT_NDISCRETES/8] ;
#endif
//Slave mode:Coils variables //Slave mode:Coils variables
USHORT usSCoilStart = S_COIL_START; rt_uint16_t usSCoilStart = S_COIL_START;
#if S_COIL_NCOILS%8 rt_uint8_t ucSCoilBuf[(S_COIL_NCOILS+7)/8];
UCHAR ucSCoilBuf[S_COIL_NCOILS/8+1] ;
#else
UCHAR ucSCoilBuf[S_COIL_NCOILS/8] ;
#endif
//Slave mode:InputRegister variables //Slave mode:InputRegister variables
USHORT usSRegInStart = S_REG_INPUT_START; rt_uint16_t usSRegInStart = S_REG_INPUT_START;
USHORT usSRegInBuf[S_REG_INPUT_NREGS] ; rt_uint16_t usSRegInBuf[S_REG_INPUT_NREGS];
//Slave mode:HoldingRegister variables //Slave mode:HoldingRegister variables
USHORT usSRegHoldStart = S_REG_HOLDING_START; rt_uint16_t usSRegHoldStart = S_REG_HOLDING_START;
USHORT usSRegHoldBuf[S_REG_HOLDING_NREGS] ; rt_uint16_t usSRegHoldBuf[S_REG_HOLDING_NREGS];
/** /**
* Modbus slave input register callback function. * Modbus slave input register callback function.
@@ -51,14 +31,14 @@ USHORT usSRegHoldBuf[S_REG_HOLDING_NREGS] ;
* *
* @return result * @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; eMBErrorCode eStatus = MB_ENOERR;
USHORT iRegIndex; rt_uint16_t iRegIndex;
USHORT * pusRegInputBuf; rt_uint16_t * pusRegInputBuf;
USHORT REG_INPUT_START; rt_uint16_t REG_INPUT_START;
USHORT REG_INPUT_NREGS; rt_uint16_t REG_INPUT_NREGS;
USHORT usRegInStart; rt_uint16_t usRegInStart;
pusRegInputBuf = usSRegInBuf; pusRegInputBuf = usSRegInBuf;
REG_INPUT_START = S_REG_INPUT_START; REG_INPUT_START = S_REG_INPUT_START;
@@ -74,8 +54,8 @@ eMBErrorCode eMBRegInputCB(UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNReg
iRegIndex = usAddress - usRegInStart; iRegIndex = usAddress - usRegInStart;
while (usNRegs > 0) while (usNRegs > 0)
{ {
*pucRegBuffer++ = (UCHAR) (pusRegInputBuf[iRegIndex] >> 8); *pucRegBuffer++ = (rt_uint8_t) (pusRegInputBuf[iRegIndex] >> 8);
*pucRegBuffer++ = (UCHAR) (pusRegInputBuf[iRegIndex] & 0xFF); *pucRegBuffer++ = (rt_uint8_t) (pusRegInputBuf[iRegIndex] & 0xFF);
iRegIndex++; iRegIndex++;
usNRegs--; usNRegs--;
} }
@@ -98,15 +78,15 @@ eMBErrorCode eMBRegInputCB(UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNReg
* *
* @return result * @return result
*/ */
eMBErrorCode eMBRegHoldingCB(UCHAR * pucRegBuffer, USHORT usAddress, eMBErrorCode eMBRegHoldingCB(rt_uint8_t * pucRegBuffer, rt_uint16_t usAddress,
USHORT usNRegs, eMBRegisterMode eMode) rt_uint16_t usNRegs, eMBRegisterMode eMode)
{ {
eMBErrorCode eStatus = MB_ENOERR; eMBErrorCode eStatus = MB_ENOERR;
USHORT iRegIndex; rt_uint16_t iRegIndex;
USHORT * pusRegHoldingBuf; rt_uint16_t * pusRegHoldingBuf;
USHORT REG_HOLDING_START; rt_uint16_t REG_HOLDING_START;
USHORT REG_HOLDING_NREGS; rt_uint16_t REG_HOLDING_NREGS;
USHORT usRegHoldStart; rt_uint16_t usRegHoldStart;
pusRegHoldingBuf = usSRegHoldBuf; pusRegHoldingBuf = usSRegHoldBuf;
REG_HOLDING_START = S_REG_HOLDING_START; REG_HOLDING_START = S_REG_HOLDING_START;
@@ -126,8 +106,8 @@ eMBErrorCode eMBRegHoldingCB(UCHAR * pucRegBuffer, USHORT usAddress,
case MB_REG_READ: case MB_REG_READ:
while (usNRegs > 0) while (usNRegs > 0)
{ {
*pucRegBuffer++ = (UCHAR) (pusRegHoldingBuf[iRegIndex] >> 8); *pucRegBuffer++ = (rt_uint8_t) (pusRegHoldingBuf[iRegIndex] >> 8);
*pucRegBuffer++ = (UCHAR) (pusRegHoldingBuf[iRegIndex] & 0xFF); *pucRegBuffer++ = (rt_uint8_t) (pusRegHoldingBuf[iRegIndex] & 0xFF);
iRegIndex++; iRegIndex++;
usNRegs--; usNRegs--;
} }
@@ -162,15 +142,15 @@ eMBErrorCode eMBRegHoldingCB(UCHAR * pucRegBuffer, USHORT usAddress,
* *
* @return result * @return result
*/ */
eMBErrorCode eMBRegCoilsCB(UCHAR * pucRegBuffer, USHORT usAddress, eMBErrorCode eMBRegCoilsCB(rt_uint8_t * pucRegBuffer, rt_uint16_t usAddress,
USHORT usNCoils, eMBRegisterMode eMode) rt_uint16_t usNCoils, eMBRegisterMode eMode)
{ {
eMBErrorCode eStatus = MB_ENOERR; eMBErrorCode eStatus = MB_ENOERR;
USHORT iRegIndex , iRegBitIndex , iNReg; rt_uint16_t iRegIndex , iRegBitIndex , iNReg;
UCHAR * pucCoilBuf; rt_uint8_t * pucCoilBuf;
USHORT COIL_START; rt_uint16_t COIL_START;
USHORT COIL_NCOILS; rt_uint16_t COIL_NCOILS;
USHORT usCoilStart; rt_uint16_t usCoilStart;
iNReg = usNCoils / 8 + 1; iNReg = usNCoils / 8 + 1;
pucCoilBuf = ucSCoilBuf; pucCoilBuf = ucSCoilBuf;
@@ -184,8 +164,8 @@ eMBErrorCode eMBRegCoilsCB(UCHAR * pucRegBuffer, USHORT usAddress,
if( ( usAddress >= COIL_START ) && if( ( usAddress >= COIL_START ) &&
( usAddress + usNCoils <= COIL_START + COIL_NCOILS ) ) ( usAddress + usNCoils <= COIL_START + COIL_NCOILS ) )
{ {
iRegIndex = (USHORT) (usAddress - usCoilStart) / 8; iRegIndex = (rt_uint16_t) (usAddress - usCoilStart) / 8;
iRegBitIndex = (USHORT) (usAddress - usCoilStart) % 8; iRegBitIndex = (rt_uint16_t) (usAddress - usCoilStart) % 8;
switch ( eMode ) switch ( eMode )
{ {
/* read current coil values from the protocol stack. */ /* read current coil values from the protocol stack. */
@@ -239,14 +219,14 @@ eMBErrorCode eMBRegCoilsCB(UCHAR * pucRegBuffer, USHORT usAddress,
* *
* @return result * @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; eMBErrorCode eStatus = MB_ENOERR;
USHORT iRegIndex , iRegBitIndex , iNReg; rt_uint16_t iRegIndex , iRegBitIndex , iNReg;
UCHAR * pucDiscreteInputBuf; rt_uint8_t * pucDiscreteInputBuf;
USHORT DISCRETE_INPUT_START; rt_uint16_t DISCRETE_INPUT_START;
USHORT DISCRETE_INPUT_NDISCRETES; rt_uint16_t DISCRETE_INPUT_NDISCRETES;
USHORT usDiscreteInputStart; rt_uint16_t usDiscreteInputStart;
iNReg = usNDiscrete / 8 + 1; iNReg = usNDiscrete / 8 + 1;
pucDiscreteInputBuf = ucSDiscInBuf; pucDiscreteInputBuf = ucSDiscInBuf;
@@ -260,8 +240,8 @@ eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT us
if ((usAddress >= DISCRETE_INPUT_START) if ((usAddress >= DISCRETE_INPUT_START)
&& (usAddress + usNDiscrete <= DISCRETE_INPUT_START + DISCRETE_INPUT_NDISCRETES)) && (usAddress + usNDiscrete <= DISCRETE_INPUT_START + DISCRETE_INPUT_NDISCRETES))
{ {
iRegIndex = (USHORT) (usAddress - usDiscreteInputStart) / 8; iRegIndex = (rt_uint16_t) (usAddress - usDiscreteInputStart) / 8;
iRegBitIndex = (USHORT) (usAddress - usDiscreteInputStart) % 8; iRegBitIndex = (rt_uint16_t) (usAddress - usDiscreteInputStart) % 8;
while (iNReg > 0) while (iNReg > 0)
{ {
+26
View File
@@ -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
-20
View File
@@ -209,26 +209,6 @@
/* IoT - internet of things */ /* 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 */ /* Wi-Fi */
-69
View File
@@ -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')
-486
View File
@@ -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
-58
View File
@@ -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
-141
View File
@@ -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;
}
-416
View File
@@ -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
-145
View File
@@ -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
-89
View File
@@ -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
-82
View File
@@ -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
-207
View File
@@ -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
-85
View File
@@ -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
-412
View File
@@ -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;
}
-429
View File
@@ -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
-36
View File
@@ -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
-66
View File
@@ -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
-446
View File
@@ -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
-158
View File
@@ -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
-55
View File
@@ -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
-49
View File
@@ -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);
}
-61
View File
@@ -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
-68
View File
@@ -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;
}
-244
View File
@@ -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
-233
View File
@@ -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
-134
View File
@@ -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
-63
View File
@@ -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();
}
-107
View File
@@ -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
-46
View File
@@ -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
-294
View File
@@ -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
-57
View File
@@ -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 这两个软件的配合。
![1561348568591](figures/run.png)
### 运行主机示例
首先下载安装和主机示例代码配合的 Modbus slave 软件。
然后,在命令行输入 `mb_master_sample` 命令就可以运行主机的示例代码。
运行之后,打开 Modbus slave 软件,点击菜单“Setup”中“Slave Definition.. F2”进行参数设置。
![img](figures/slave_cfg.png)
点击菜单“Connection”中“Connect.. F3”进行连接。弹出连接对话框,根据具体情况配置:
![1561351899477](figures/slave_con.png)
连接成功,可以看到寄存器列表中的第 2、3个寄存器的数值在不断变化。
![1561352048209](figures/slave_run.png)
### 运行从机示例
从机的运行示例和主机相差不大,只是 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

-117
View File
@@ -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);
-139
View File
@@ -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);