Resync new repository with old repo r5166

git-svn-id: http://svn.code.sf.net/p/nuttx/code/trunk@5153 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo
2012-09-17 18:18:44 +00:00
commit 57623d42eb
5691 changed files with 1361853 additions and 0 deletions
+143
View File
@@ -0,0 +1,143 @@
#
# For a description of the syntax of this configuration file,
# see misc/tools/kconfig-language.txt.
#
comment "FreeModbus"
config MODBUS
bool "Modbus support via FreeModBus"
default n
config MB_ASCII_ENABLED
bool "Modbus ASCII support"
depends on MODBUS
default y
config MB_RTU_ENABLED
bool "Modbus RTU support"
depends on MODBUS
default y
config MB_TCP_ENABLED
bool "Modbus TCP support"
depends on MODBUS
default y
config MB_ASCII_TIMEOUT_SEC
int "Character timeout"
depends on MB_ASCII_ENABLED
default 1
---help---
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.
config MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS
int "Timeout to wait before sending"
depends on MB_ASCII_ENABLED
default 0
---help---
Timeout to wait in ASCII prior to enabling transmitter
If defined the function calls vMBPortSerialDelay with the argument
MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS to allow for a delay before
the serial transmitter is enabled. This is required because some
targets are so fast that there is no time between receiving and
transmitting the frame. If the master is to slow with enabling its
receiver then he will not receive the response correctly.
config MB_FUNC_HANDLERS_MAX
int "Maximum number of Modbus functions"
depends on MODBUS
default 16
---help---
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.
config MB_FUNC_OTHER_REP_SLAVEID_BUF
int "Size of Slave ID report buffer"
depends on MB_FUNC_OTHER_REP_SLAVEID_ENABLED
default 32
---help---
Number of bytes which should be allocated for the Report Slave ID 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 1.
config MB_FUNC_OTHER_REP_SLAVEID_ENABLED
bool "Report Slave ID function"
depends on MODBUS
default y
---help---
If the Report Slave ID function should be enabled.
config MB_FUNC_READ_INPUT_ENABLED
bool "Read Input Registers function"
depends on MODBUS
default y
---help---
If the Read Input Registers function should be enabled.
config MB_FUNC_READ_HOLDING_ENABLED
bool "Read Holding Registers function"
depends on MODBUS
default y
---help---
If the Read Holding Registers function should be enabled.
config MB_FUNC_WRITE_HOLDING_ENABLED
bool "Write Single Register function"
depends on MODBUS
default y
---help---
If the Write Single Register function should be enabled.
config MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED
bool "Write Multiple registers function"
depends on MODBUS
default y
---help---
If the Write Multiple registers function should be enabled.
config MB_FUNC_READ_COILS_ENABLED
bool "Read Coils function"
depends on MODBUS
default y
---help---
If the Read Coils function should be enabled.
config MB_FUNC_WRITE_COIL_ENABLED
bool "Write Coils function"
depends on MODBUS
default y
---help---
If the Write Coils function should be enabled.
config MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED
bool "Write Multiple Coils function"
depends on MODBUS
default y
---help---
If the Write Multiple Coils function should be enabled.
config MB_FUNC_READ_DISCRETE_INPUTS_ENABLED
bool "Read Discrete Inputs function"
depends on MODBUS
default y
---help---
If the Read Discrete Inputs function should be enabled.
config MB_FUNC_READWRITE_HOLDING_ENABLED
bool "Read/Write Multiple Registers function"
depends on MODBUS
default y
---help---
If the Read/Write Multiple Registers function should be enabled.
+40
View File
@@ -0,0 +1,40 @@
############################################################################
# apps/modbus/Make.defs
# Adds selected applications to apps/ build
#
# Copyright (C) 2012 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt <gnutt@nuttx.org>
#
# 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. Neither the name NuttX nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "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
# COPYRIGHT OWNER OR CONTRIBUTORS 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.
#
############################################################################
ifeq ($(CONFIG_MODBUS),y)
CONFIGURED_APPS += modbus
endif
+116
View File
@@ -0,0 +1,116 @@
############################################################################
# apps/modbus/Makefile
#
# Copyright (C) 2012 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt <gnutt@nuttx.org>
#
# 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. Neither the name NuttX nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "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
# COPYRIGHT OWNER OR CONTRIBUTORS 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.
#
############################################################################
-include $(TOPDIR)/.config
-include $(TOPDIR)/Make.defs
include $(APPDIR)/Make.defs
# FreeModBus Library
ASRCS =
CSRCS =
ifeq ($(CONFIG_MODBUS),y)
CSRCS += mb.c
DEPPATH = --dep-path .
VPATH = .
ifeq ($(WINTOOL),y)
INCDIROPT = -w
endif
include ascii/Make.defs
include functions/Make.defs
include nuttx/Make.defs
include rtu/Make.defs
include tcp/Make.defs
endif
AOBJS = $(ASRCS:.S=$(OBJEXT))
COBJS = $(CSRCS:.c=$(OBJEXT))
SRCS = $(ASRCS) $(CSRCS)
OBJS = $(AOBJS) $(COBJS)
ifeq ($(WINTOOL),y)
BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}"
else
BIN = "$(APPDIR)/libapps$(LIBEXT)"
endif
# Build targets
all: .built
.PHONY: context .depend depend clean distclean
ifeq ($(CONFIG_MODBUS),y)
$(AOBJS): %$(OBJEXT): %.S
$(call ASSEMBLE, $<, $@)
$(COBJS): %$(OBJEXT): %.c
$(call COMPILE, $<, $@)
endif
.built: $(OBJS)
ifeq ($(CONFIG_MODBUS),y)
@( for obj in $(OBJS) ; do \
$(call ARCHIVE, $(BIN), $${obj}); \
done ; )
@touch .built
endif
context:
.depend: Makefile $(SRCS)
ifeq ($(CONFIG_MODBUS),y)
@$(MKDEP) $(DEPPATH) \
$(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep
@touch $@
endif
depend: .depend
clean:
@rm -f *.o *~ .*.swp .built
$(call CLEAN)
distclean: clean
@rm -f Make.dep .depend
-include Make.dep
+117
View File
@@ -0,0 +1,117 @@
apps/modbus README
==================
This directory contains a port of last open source version of FreeModBus
(BSD license). The code in this directory is a subset of FreeModBus version
1.5.0 (June 6, 2010) that can be downloaded in its entirety from http://developer.berlios.de/project/showfiles.php?group_id=6120.
Directory Structure/Relation to freemodbus-v1.5.0
-------------------------------------------------
The original FreeModBus download consists of several directories. This
subset takes only the contents of one directory, modbus/, that implements
the core modbus logic and integrates that directory into the NuttX build
system. The mapping between freemodbus-v1.5.0 and the nuttx directories
is shown below:
--------------------------- ----------------------------------------------
freemodbus-v1.5.0 Nuttx
--------------------------- ----------------------------------------------
All top level .txt files Not included
demo/ Not included. This directory contains demo
and porting code for a variety of platforms.
The NuttX demo was ported from the the LINUX
demo in this director and can be found at
apps/examples/modbus.
doc/ Note included. This directory contains Doxygen
support files.
modbus/ Included in its entirety in various locations:
ascii apps/modbus/ascii
functions apps/modbus/functions
include apps/include/modbus
mb.c apps/modbus/mb.c
rtu apps/modbus/rtu
tcp apps/modbus/tcp
tools/ Note included. This directory contain Doxygen
tools.
--------------------------- ----------------------------------------------
So this directory is equivalent to the freemodbus-v1.5.0/modbus
directory except that (1) it may include modifications for the integration
with NuttX and (2) the modbus/include directory was moved to apps/modbus.
The original, unmodified freemodbus-v1.5.0 was checked in as SVN revision
4960.
The other directory here, nuttx/, implements the NuttX modbus interface.
It derives from the freemodbus-v1.5.0/demo/LINUX/port directory.
Configuration Options
=====================
In the original freemodbus-v1.5.0 release, the FreeModBus configuration
was controlled by the header file mbconfig.h. This header file was
eliminated (post revision 4960) and the FreeModBus configuration
was integrated into the NuttX configuration system.
The NuttX-named configuration options that are available include:
CONFIG_MODBUS - General ModBus support
CONFIG_MB_ASCII_ENABLED - Modbus ASCII support
CONFIG_MB_RTU_ENABLED - Modbus RTU support
CONFIG_MB_TCP_ENABLED - Modbus TCP support
CONFIG_MB_ASCII_TIMEOUT_SEC - 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. Default 1
CONFIG_MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS - Timeout to wait in ASCII prior
to enabling transmitter. If defined the function calls
vMBPortSerialDelay with the argument CONFIG_MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS
to allow for a delay before the serial transmitter is enabled. This is
required because some targets are so fast that there is no time between
receiving and transmitting the frame. If the master is to slow with
enabling its receiver then he will not receive the response correctly.
CONFIG_MB_FUNC_HANDLERS_MAX - 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.
CONFIG_MB_FUNC_OTHER_REP_SLAVEID_BUF - Number of bytes which should be
allocated for the Report Slave ID 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 CONFIG_MB_FUNC_OTHER_REP_SLAVEID_ENABLED is set to 1.
CONFIG_MB_FUNC_OTHER_REP_SLAVEID_ENABLED - If the Report Slave ID
function should be enabled.
CONFIG_MB_FUNC_READ_INPUT_ENABLED - If the Read Input Registers function
should be enabled.
CONFIG_MB_FUNC_READ_HOLDING_ENABLED - If the Read Holding Registers
function should be enabled.
CONFIG_MB_FUNC_WRITE_HOLDING_ENABLED - If the Write Single Register
function should be enabled.
CONFIG_MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED - If the Write Multiple
registers function should be enabled.
CONFIG_MB_FUNC_READ_COILS_ENABLED - If the Read Coils function should
be enabled.
CONFIG_MB_FUNC_WRITE_COIL_ENABLED - If the Write Coils function should
be enabled.
CONFIG_MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED - If the Write Multiple Coils
function should be enabled.
CONFIG_MB_FUNC_READ_DISCRETE_INPUTS_ENABLED - If the Read Discrete Inputs
function should be enabled.
CONFIG_MB_FUNC_READWRITE_HOLDING_ENABLED - If the Read/Write Multiple
Registers function should be enabled.
See also other serial settings, in particular:
CONFIG_SERIAL_TERMIOS - Serial driver supports termios.h interfaces (tcsetattr,
tcflush, etc.). If this is not defined, then the terminal settings (baud,
parity, etc.) are not configurable at runtime; serial streams will not be
flushed when closed.
Note
====
The developer of FreeModBus, Christian Walter, is still developing Modbus
libraries, although they are now commercial. See
http://www.embedded-solutions.at/ for further information.
+44
View File
@@ -0,0 +1,44 @@
############################################################################
# apps/modbus/functions/Make.defs
#
# Copyright (C) 2012 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt <gnutt@nuttx.org>
#
# 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. Neither the name NuttX nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "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
# COPYRIGHT OWNER OR CONTRIBUTORS 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.
#
############################################################################
ifeq ($(CONFIG_MB_ASCII_ENABLED),y)
CSRCS += mbascii.c
DEPPATH += --dep-path ascii
VPATH += :ascii
CFLAGS += ${shell $(TOPDIR)/tools/incdir.sh $(INCDIROPT) "$(CC)" $(APPDIR)/modbus/ascii}
endif
+487
View File
@@ -0,0 +1,487 @@
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbascii.c,v 1.17 2010/06/06 13:47:07 wolti Exp $
*/
/* ----------------------- System includes ----------------------------------*/
#include <nuttx/config.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include <apps/modbus/mb.h>
#include <apps/modbus/mbframe.h>
#include <apps/modbus/mbport.h>
#include "mbascii.h"
#include "mbcrc.h"
#ifdef CONFIG_MB_ASCII_ENABLED
/* ----------------------- 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 uint8_t prvucMBint8_t2BIN( uint8_t ucCharacter );
static uint8_t prvucMBBIN2int8_t( uint8_t ucByte );
static uint8_t prvucMBLRC( uint8_t * pucFrame, uint16_t 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 uint8_t ucRTUBuf[];
static volatile uint8_t *ucASCIIBuf = ucRTUBuf;
static volatile uint16_t usRcvBufferPos;
static volatile eMBBytePos eBytePos;
static volatile uint8_t *pucSndBufferCur;
static volatile uint16_t usSndBufferCount;
static volatile uint8_t ucLRC;
static volatile uint8_t ucMBLFCharacter;
/* ----------------------- Start implementation -----------------------------*/
eMBErrorCode
eMBASCIIInit( uint8_t ucSlaveAddress, uint8_t ucPort, speed_t 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( CONFIG_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( uint8_t * pucRcvAddress, uint8_t ** pucFrame, uint16_t * 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( ( uint8_t * ) 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 = ( uint16_t )( usRcvBufferPos - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_LRC );
/* Return the start of the Modbus PDU to the caller. */
*pucFrame = ( uint8_t * ) & ucASCIIBuf[MB_SER_PDU_PDU_OFF];
}
else
{
eStatus = MB_EIO;
}
EXIT_CRITICAL_SECTION( );
return eStatus;
}
eMBErrorCode
eMBASCIISend( uint8_t ucSlaveAddress, const uint8_t * pucFrame, uint16_t usLength )
{
eMBErrorCode eStatus = MB_ENOERR;
uint8_t 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 = ( uint8_t * ) 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( ( uint8_t * ) 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;
uint8_t ucByte;
uint8_t ucResult;
ASSERT( eSndState == STATE_TX_IDLE );
( void )xMBPortSerialGetByte( ( int8_t * ) & 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 = prvucMBint8_t2BIN( 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] = ( uint8_t )( 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;
uint8_t 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( ( int8_t )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 = prvucMBBIN2int8_t( ( uint8_t )( *pucSndBufferCur >> 4 ) );
xMBPortSerialPutByte( ( int8_t ) ucByte );
eBytePos = BYTE_LOW_NIBBLE;
break;
case BYTE_LOW_NIBBLE:
ucByte = prvucMBBIN2int8_t( ( uint8_t )( *pucSndBufferCur & 0x0F ) );
xMBPortSerialPutByte( ( int8_t )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( ( int8_t )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 uint8_t
prvucMBint8_t2BIN( uint8_t ucCharacter )
{
if( ( ucCharacter >= '0' ) && ( ucCharacter <= '9' ) )
{
return ( uint8_t )( ucCharacter - '0' );
}
else if( ( ucCharacter >= 'A' ) && ( ucCharacter <= 'F' ) )
{
return ( uint8_t )( ucCharacter - 'A' + 0x0A );
}
else
{
return 0xFF;
}
}
static uint8_t
prvucMBBIN2int8_t( uint8_t ucByte )
{
if( ucByte <= 0x09 )
{
return ( uint8_t )( '0' + ucByte );
}
else if( ( ucByte >= 0x0A ) && ( ucByte <= 0x0F ) )
{
return ( uint8_t )( ucByte - 0x0A + 'A' );
}
else
{
/* Programming error. */
ASSERT( 0 );
}
return '0';
}
static uint8_t
prvucMBLRC( uint8_t * pucFrame, uint16_t usLen )
{
uint8_t ucLocalLRC = 0; /* LRC char initialized */
while( usLen-- )
{
ucLocalLRC += *pucFrame++; /* Add buffer byte without carry */
}
/* Return twos complement */
ucLocalLRC = ( uint8_t ) ( -( ( int8_t ) ucLocalLRC ) );
return ucLocalLRC;
}
#endif
+56
View File
@@ -0,0 +1,56 @@
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbascii.h,v 1.8 2006/12/07 22:10:34 wolti Exp $
*/
#ifndef _MB_ASCII_H
#define _MB_ASCII_H
#ifdef __cplusplus
PR_BEGIN_EXTERN_C
#endif
#ifdef CONFIG_MB_ASCII_ENABLED
eMBErrorCode eMBASCIIInit( uint8_t slaveAddress, uint8_t ucPort,
speed_t ulBaudRate, eMBParity eParity );
void eMBASCIIStart( void );
void eMBASCIIStop( void );
eMBErrorCode eMBASCIIReceive( uint8_t * pucRcvAddress, uint8_t ** pucFrame,
uint16_t * pusLength );
eMBErrorCode eMBASCIISend( uint8_t slaveAddress, const uint8_t * pucFrame,
uint16_t usLength );
bool xMBASCIIReceiveFSM( void );
bool xMBASCIITransmitFSM( void );
bool xMBASCIITimerT1SExpired( void );
#endif
#ifdef __cplusplus
PR_END_EXTERN_C
#endif
#endif
+41
View File
@@ -0,0 +1,41 @@
############################################################################
# apps/modbus/nuttx/Make.defs
#
# Copyright (C) 2012 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt <gnutt@nuttx.org>
#
# 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. Neither the name NuttX nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "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
# COPYRIGHT OWNER OR CONTRIBUTORS 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.
#
############################################################################
CSRCS += mbfunccoils.c mbfuncdiag.c mbfuncdisc.c mbfuncholding.c
CSRCS += mbfuncinput.c mbfuncother.c mbutils.c
DEPPATH += --dep-path functions
VPATH += :functions
CFLAGS += ${shell $(TOPDIR)/tools/incdir.sh $(INCDIROPT) "$(CC)" $(APPDIR)/modbus/functions}
+270
View File
@@ -0,0 +1,270 @@
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbfunccoils.c,v 1.8 2007/02/18 23:47:16 wolti Exp $
*/
/* ----------------------- System includes ----------------------------------*/
#include <nuttx/config.h>
#include <stdlib.h>
#include <string.h>
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include <apps/modbus/mb.h>
#include <apps/modbus/mbframe.h>
#include <apps/modbus/mbproto.h>
/* ----------------------- Defines ------------------------------------------*/
#define MB_PDU_FUNC_READ_ADDR_OFF ( MB_PDU_DATA_OFF )
#define MB_PDU_FUNC_READ_COILCNT_OFF ( MB_PDU_DATA_OFF + 2 )
#define MB_PDU_FUNC_READ_SIZE ( 4 )
#define MB_PDU_FUNC_READ_COILCNT_MAX ( 0x07D0 )
#define MB_PDU_FUNC_WRITE_ADDR_OFF ( MB_PDU_DATA_OFF )
#define MB_PDU_FUNC_WRITE_VALUE_OFF ( MB_PDU_DATA_OFF + 2 )
#define MB_PDU_FUNC_WRITE_SIZE ( 4 )
#define MB_PDU_FUNC_WRITE_MUL_ADDR_OFF ( MB_PDU_DATA_OFF )
#define MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF ( MB_PDU_DATA_OFF + 2 )
#define MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF ( MB_PDU_DATA_OFF + 4 )
#define MB_PDU_FUNC_WRITE_MUL_VALUES_OFF ( MB_PDU_DATA_OFF + 5 )
#define MB_PDU_FUNC_WRITE_MUL_SIZE_MIN ( 5 )
#define MB_PDU_FUNC_WRITE_MUL_COILCNT_MAX ( 0x07B0 )
/* ----------------------- Static functions ---------------------------------*/
eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
/* ----------------------- Start implementation -----------------------------*/
#ifdef CONFIG_MB_FUNC_READ_COILS_ENABLED
eMBException
eMBFuncReadCoils( uint8_t * pucFrame, uint16_t * usLen )
{
uint16_t usRegAddress;
uint16_t usCoilCount;
uint8_t ucNBytes;
uint8_t *pucFrameCur;
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
{
usRegAddress = ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
usRegAddress |= ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
usRegAddress++;
usCoilCount = ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_COILCNT_OFF] << 8 );
usCoilCount |= ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_COILCNT_OFF + 1] );
/* Check if the number of registers to read is valid. If not
* return Modbus illegal data value exception.
*/
if( ( usCoilCount >= 1 ) &&
( usCoilCount < MB_PDU_FUNC_READ_COILCNT_MAX ) )
{
/* Set the current PDU data pointer to the beginning. */
pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
*usLen = MB_PDU_FUNC_OFF;
/* First byte contains the function code. */
*pucFrameCur++ = MB_FUNC_READ_COILS;
*usLen += 1;
/* Test if the quantity of coils is a multiple of 8. If not last
* byte is only partially field with unused coils set to zero. */
if( ( usCoilCount & 0x0007 ) != 0 )
{
ucNBytes = ( uint8_t )( usCoilCount / 8 + 1 );
}
else
{
ucNBytes = ( uint8_t )( usCoilCount / 8 );
}
*pucFrameCur++ = ucNBytes;
*usLen += 1;
eRegStatus =
eMBRegCoilsCB( pucFrameCur, usRegAddress, usCoilCount,
MB_REG_READ );
/* If an error occured convert it into a Modbus exception. */
if( eRegStatus != MB_ENOERR )
{
eStatus = prveMBError2Exception( eRegStatus );
}
else
{
/* The response contains the function code, the starting address
* and the quantity of registers. We reuse the old values in the
* buffer because they are still valid. */
*usLen += ucNBytes;;
}
}
else
{
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
}
else
{
/* Can't be a valid read coil register request because the length
* is incorrect. */
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
return eStatus;
}
#ifdef CONFIG_MB_FUNC_WRITE_COIL_ENABLED
eMBException
eMBFuncWriteCoil( uint8_t * pucFrame, uint16_t * usLen )
{
uint16_t usRegAddress;
uint8_t ucBuf[2];
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
if( *usLen == ( MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN ) )
{
usRegAddress = ( uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF] << 8 );
usRegAddress |= ( uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF + 1] );
usRegAddress++;
if( ( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF + 1] == 0x00 ) &&
( ( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0xFF ) ||
( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0x00 ) ) )
{
ucBuf[1] = 0;
if( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0xFF )
{
ucBuf[0] = 1;
}
else
{
ucBuf[0] = 0;
}
eRegStatus =
eMBRegCoilsCB( &ucBuf[0], usRegAddress, 1, MB_REG_WRITE );
/* If an error occured convert it into a Modbus exception. */
if( eRegStatus != MB_ENOERR )
{
eStatus = prveMBError2Exception( eRegStatus );
}
}
else
{
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
}
else
{
/* Can't be a valid write coil register request because the length
* is incorrect. */
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
return eStatus;
}
#endif
#ifdef CONFIG_MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED
eMBException
eMBFuncWriteMultipleCoils( uint8_t * pucFrame, uint16_t * usLen )
{
uint16_t usRegAddress;
uint16_t usCoilCnt;
uint8_t ucByteCount;
uint8_t ucByteCountVerify;
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
if( *usLen > ( MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN ) )
{
usRegAddress = ( uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF] << 8 );
usRegAddress |= ( uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF + 1] );
usRegAddress++;
usCoilCnt = ( uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF] << 8 );
usCoilCnt |= ( uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF + 1] );
ucByteCount = pucFrame[MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF];
/* Compute the number of expected bytes in the request. */
if( ( usCoilCnt & 0x0007 ) != 0 )
{
ucByteCountVerify = ( uint8_t )( usCoilCnt / 8 + 1 );
}
else
{
ucByteCountVerify = ( uint8_t )( usCoilCnt / 8 );
}
if( ( usCoilCnt >= 1 ) &&
( usCoilCnt <= MB_PDU_FUNC_WRITE_MUL_COILCNT_MAX ) &&
( ucByteCountVerify == ucByteCount ) )
{
eRegStatus =
eMBRegCoilsCB( &pucFrame[MB_PDU_FUNC_WRITE_MUL_VALUES_OFF],
usRegAddress, usCoilCnt, MB_REG_WRITE );
/* If an error occured convert it into a Modbus exception. */
if( eRegStatus != MB_ENOERR )
{
eStatus = prveMBError2Exception( eRegStatus );
}
else
{
/* The response contains the function code, the starting address
* and the quantity of registers. We reuse the old values in the
* buffer because they are still valid. */
*usLen = MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF;
}
}
else
{
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
}
else
{
/* Can't be a valid write coil register request because the length
* is incorrect. */
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
return eStatus;
}
#endif
#endif
+29
View File
@@ -0,0 +1,29 @@
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbfuncdiag.c,v 1.3 2006/12/07 22:10:34 wolti Exp $
*/
+123
View File
@@ -0,0 +1,123 @@
/*
* FreeRTOS Modbus Libary: A Modbus serial implementation for FreeRTOS
* Copyright (C) 2006 Christian Walter <wolti@sil.at>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* ----------------------- System includes ----------------------------------*/
#include <nuttx/config.h>
#include <stdlib.h>
#include <string.h>
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include <apps/modbus/mb.h>
#include <apps/modbus/mbframe.h>
#include <apps/modbus/mbproto.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 -----------------------------*/
#ifdef CONFIG_MB_FUNC_READ_COILS_ENABLED
eMBException
eMBFuncReadDiscreteInputs( uint8_t * pucFrame, uint16_t * usLen )
{
uint16_t usRegAddress;
uint16_t usDiscreteCnt;
uint8_t ucNBytes;
uint8_t *pucFrameCur;
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
{
usRegAddress = ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
usRegAddress |= ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
usRegAddress++;
usDiscreteCnt = ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_DISCCNT_OFF] << 8 );
usDiscreteCnt |= ( 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 = ( uint8_t ) ( usDiscreteCnt / 8 + 1 );
}
else
{
ucNBytes = ( 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;
}
#endif
+308
View File
@@ -0,0 +1,308 @@
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbfuncholding.c,v 1.12 2007/02/18 23:48:22 wolti Exp $
*/
/* ----------------------- System includes ----------------------------------*/
#include <nuttx/config.h>
#include <stdlib.h>
#include <string.h>
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include <apps/modbus/mb.h>
#include <apps/modbus/mbframe.h>
#include <apps/modbus/mbproto.h>
/* ----------------------- Defines ------------------------------------------*/
#define MB_PDU_FUNC_READ_ADDR_OFF ( MB_PDU_DATA_OFF + 0)
#define MB_PDU_FUNC_READ_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 )
#define MB_PDU_FUNC_READ_SIZE ( 4 )
#define MB_PDU_FUNC_READ_REGCNT_MAX ( 0x007D )
#define MB_PDU_FUNC_WRITE_ADDR_OFF ( MB_PDU_DATA_OFF + 0)
#define MB_PDU_FUNC_WRITE_VALUE_OFF ( MB_PDU_DATA_OFF + 2 )
#define MB_PDU_FUNC_WRITE_SIZE ( 4 )
#define MB_PDU_FUNC_WRITE_MUL_ADDR_OFF ( MB_PDU_DATA_OFF + 0 )
#define MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 )
#define MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF ( MB_PDU_DATA_OFF + 4 )
#define MB_PDU_FUNC_WRITE_MUL_VALUES_OFF ( MB_PDU_DATA_OFF + 5 )
#define MB_PDU_FUNC_WRITE_MUL_SIZE_MIN ( 5 )
#define MB_PDU_FUNC_WRITE_MUL_REGCNT_MAX ( 0x0078 )
#define MB_PDU_FUNC_READWRITE_READ_ADDR_OFF ( MB_PDU_DATA_OFF + 0 )
#define MB_PDU_FUNC_READWRITE_READ_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 )
#define MB_PDU_FUNC_READWRITE_WRITE_ADDR_OFF ( MB_PDU_DATA_OFF + 4 )
#define MB_PDU_FUNC_READWRITE_WRITE_REGCNT_OFF ( MB_PDU_DATA_OFF + 6 )
#define MB_PDU_FUNC_READWRITE_BYTECNT_OFF ( MB_PDU_DATA_OFF + 8 )
#define MB_PDU_FUNC_READWRITE_WRITE_VALUES_OFF ( MB_PDU_DATA_OFF + 9 )
#define MB_PDU_FUNC_READWRITE_SIZE_MIN ( 9 )
/* ----------------------- Static functions ---------------------------------*/
eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
/* ----------------------- Start implementation -----------------------------*/
#ifdef CONFIG_MB_FUNC_WRITE_HOLDING_ENABLED
eMBException
eMBFuncWriteHoldingRegister( uint8_t * pucFrame, uint16_t * usLen )
{
uint16_t usRegAddress;
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
if( *usLen == ( MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN ) )
{
usRegAddress = ( uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF] << 8 );
usRegAddress |= ( uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF + 1] );
usRegAddress++;
/* Make callback to update the value. */
eRegStatus = eMBRegHoldingCB( &pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF],
usRegAddress, 1, MB_REG_WRITE );
/* If an error occured convert it into a Modbus exception. */
if( eRegStatus != MB_ENOERR )
{
eStatus = prveMBError2Exception( eRegStatus );
}
}
else
{
/* Can't be a valid request because the length is incorrect. */
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
return eStatus;
}
#endif
#ifdef CONFIG_MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED
eMBException
eMBFuncWriteMultipleHoldingRegister( uint8_t * pucFrame, uint16_t * usLen )
{
uint16_t usRegAddress;
uint16_t usRegCount;
uint8_t ucRegByteCount;
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
if( *usLen >= ( MB_PDU_FUNC_WRITE_MUL_SIZE_MIN + MB_PDU_SIZE_MIN ) )
{
usRegAddress = ( uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF] << 8 );
usRegAddress |= ( uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF + 1] );
usRegAddress++;
usRegCount = ( uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF] << 8 );
usRegCount |= ( uint16_t )( pucFrame[MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF + 1] );
ucRegByteCount = pucFrame[MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF];
if( ( usRegCount >= 1 ) &&
( usRegCount <= MB_PDU_FUNC_WRITE_MUL_REGCNT_MAX ) &&
( ucRegByteCount == ( uint8_t ) ( 2 * usRegCount ) ) )
{
/* Make callback to update the register values. */
eRegStatus =
eMBRegHoldingCB( &pucFrame[MB_PDU_FUNC_WRITE_MUL_VALUES_OFF],
usRegAddress, usRegCount, MB_REG_WRITE );
/* If an error occured convert it into a Modbus exception. */
if( eRegStatus != MB_ENOERR )
{
eStatus = prveMBError2Exception( eRegStatus );
}
else
{
/* The response contains the function code, the starting
* address and the quantity of registers. We reuse the
* old values in the buffer because they are still valid.
*/
*usLen = MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF;
}
}
else
{
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
}
else
{
/* Can't be a valid request because the length is incorrect. */
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
return eStatus;
}
#endif
#ifdef CONFIG_MB_FUNC_READ_HOLDING_ENABLED
eMBException
eMBFuncReadHoldingRegister( uint8_t * pucFrame, uint16_t * usLen )
{
uint16_t usRegAddress;
uint16_t usRegCount;
uint8_t *pucFrameCur;
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
{
usRegAddress = ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
usRegAddress |= ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
usRegAddress++;
usRegCount = ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] << 8 );
usRegCount = ( 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_HOLDING_REGISTER;
*usLen += 1;
/* Second byte in the response contain the number of bytes. */
*pucFrameCur++ = ( uint8_t ) ( usRegCount * 2 );
*usLen += 1;
/* Make callback to fill the buffer. */
eRegStatus = eMBRegHoldingCB( pucFrameCur, usRegAddress, usRegCount, MB_REG_READ );
/* If an error occured convert it into a Modbus exception. */
if( eRegStatus != MB_ENOERR )
{
eStatus = prveMBError2Exception( eRegStatus );
}
else
{
*usLen += usRegCount * 2;
}
}
else
{
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
}
else
{
/* Can't be a valid request because the length is incorrect. */
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
return eStatus;
}
#endif
#ifdef CONFIG_MB_FUNC_READWRITE_HOLDING_ENABLED
eMBException
eMBFuncReadWriteMultipleHoldingRegister( uint8_t * pucFrame, uint16_t * usLen )
{
uint16_t usRegReadAddress;
uint16_t usRegReadCount;
uint16_t usRegWriteAddress;
uint16_t usRegWriteCount;
uint8_t ucRegWriteByteCount;
uint8_t *pucFrameCur;
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
if( *usLen >= ( MB_PDU_FUNC_READWRITE_SIZE_MIN + MB_PDU_SIZE_MIN ) )
{
usRegReadAddress = ( uint16_t )( pucFrame[MB_PDU_FUNC_READWRITE_READ_ADDR_OFF] << 8U );
usRegReadAddress |= ( uint16_t )( pucFrame[MB_PDU_FUNC_READWRITE_READ_ADDR_OFF + 1] );
usRegReadAddress++;
usRegReadCount = ( uint16_t )( pucFrame[MB_PDU_FUNC_READWRITE_READ_REGCNT_OFF] << 8U );
usRegReadCount |= ( uint16_t )( pucFrame[MB_PDU_FUNC_READWRITE_READ_REGCNT_OFF + 1] );
usRegWriteAddress = ( uint16_t )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_ADDR_OFF] << 8U );
usRegWriteAddress |= ( uint16_t )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_ADDR_OFF + 1] );
usRegWriteAddress++;
usRegWriteCount = ( uint16_t )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_REGCNT_OFF] << 8U );
usRegWriteCount |= ( uint16_t )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_REGCNT_OFF + 1] );
ucRegWriteByteCount = pucFrame[MB_PDU_FUNC_READWRITE_BYTECNT_OFF];
if( ( usRegReadCount >= 1 ) && ( usRegReadCount <= 0x7D ) &&
( usRegWriteCount >= 1 ) && ( usRegWriteCount <= 0x79 ) &&
( ( 2 * usRegWriteCount ) == ucRegWriteByteCount ) )
{
/* Make callback to update the register values. */
eRegStatus = eMBRegHoldingCB( &pucFrame[MB_PDU_FUNC_READWRITE_WRITE_VALUES_OFF],
usRegWriteAddress, usRegWriteCount, MB_REG_WRITE );
if( eRegStatus == MB_ENOERR )
{
/* Set the current PDU data pointer to the beginning. */
pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
*usLen = MB_PDU_FUNC_OFF;
/* First byte contains the function code. */
*pucFrameCur++ = MB_FUNC_READWRITE_MULTIPLE_REGISTERS;
*usLen += 1;
/* Second byte in the response contain the number of bytes. */
*pucFrameCur++ = ( uint8_t ) ( usRegReadCount * 2 );
*usLen += 1;
/* Make the read callback. */
eRegStatus =
eMBRegHoldingCB( pucFrameCur, usRegReadAddress, usRegReadCount, MB_REG_READ );
if( eRegStatus == MB_ENOERR )
{
*usLen += 2 * usRegReadCount;
}
}
if( eRegStatus != MB_ENOERR )
{
eStatus = prveMBError2Exception( eRegStatus );
}
}
else
{
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
}
return eStatus;
}
#endif
+122
View File
@@ -0,0 +1,122 @@
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbfuncinput.c,v 1.10 2007/09/12 10:15:56 wolti Exp $
*/
/* ----------------------- System includes ----------------------------------*/
#include <nuttx/config.h>
#include <stdlib.h>
#include <string.h>
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include <apps/modbus/mb.h>
#include <apps/modbus/mbframe.h>
#include <apps/modbus/mbproto.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 -----------------------------*/
#ifdef CONFIG_MB_FUNC_READ_INPUT_ENABLED
eMBException
eMBFuncReadInputRegister( uint8_t * pucFrame, uint16_t * usLen )
{
uint16_t usRegAddress;
uint16_t usRegCount;
uint8_t *pucFrameCur;
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
{
usRegAddress = ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
usRegAddress |= ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
usRegAddress++;
usRegCount = ( uint16_t )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] << 8 );
usRegCount |= ( 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++ = ( 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;
}
#endif
+88
View File
@@ -0,0 +1,88 @@
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbfuncother.c,v 1.8 2006/12/07 22:10:34 wolti Exp $
*/
/* ----------------------- System includes ----------------------------------*/
#include <nuttx/config.h>
#include <stdlib.h>
#include <string.h>
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include <apps/modbus/mb.h>
#include <apps/modbus/mbframe.h>
#include <apps/modbus/mbproto.h>
#ifdef CONFIG_MB_FUNC_OTHER_REP_SLAVEID_ENABLED
/* ----------------------- Static variables ---------------------------------*/
static uint8_t ucMBSlaveID[CONFIG_MB_FUNC_OTHER_REP_SLAVEID_BUF];
static uint16_t usMBSlaveIDLen;
/* ----------------------- Start implementation -----------------------------*/
eMBErrorCode
eMBSetSlaveID( uint8_t ucSlaveID, bool xIsRunning,
uint8_t const *pucAdditional, 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 < CONFIG_MB_FUNC_OTHER_REP_SLAVEID_BUF )
{
usMBSlaveIDLen = 0;
ucMBSlaveID[usMBSlaveIDLen++] = ucSlaveID;
ucMBSlaveID[usMBSlaveIDLen++] = ( 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( uint8_t * pucFrame, uint16_t * usLen )
{
memcpy( &pucFrame[MB_PDU_DATA_OFF], &ucMBSlaveID[0], ( size_t )usMBSlaveIDLen );
*usLen = ( uint16_t )( MB_PDU_DATA_OFF + usMBSlaveIDLen );
return MB_EX_NONE;
}
#endif
+143
View File
@@ -0,0 +1,143 @@
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbutils.c,v 1.6 2007/02/18 23:49:07 wolti Exp $
*/
/* ----------------------- System includes ----------------------------------*/
#include <nuttx/config.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include <apps/modbus/mb.h>
#include <apps/modbus/mbproto.h>
/* ----------------------- Defines ------------------------------------------*/
#define BITS_uint8_t 8U
/* ----------------------- Start implementation -----------------------------*/
void
xMBUtilSetBits( uint8_t * ucByteBuf, uint16_t usBitOffset, uint8_t ucNBits,
uint8_t ucValue )
{
uint16_t usWordBuf;
uint16_t usMask;
uint16_t usByteOffset;
uint16_t usNPreBits;
uint16_t usValue = ucValue;
ASSERT( ucNBits <= 8 );
ASSERT( ( size_t )BITS_uint8_t == sizeof( uint8_t ) * 8 );
/* Calculate byte offset for first byte containing the bit values starting
* at usBitOffset. */
usByteOffset = ( uint16_t )( ( usBitOffset ) / BITS_uint8_t );
/* How many bits precede our bits to set. */
usNPreBits = ( uint16_t )( usBitOffset - usByteOffset * BITS_uint8_t );
/* Move bit field into position over bits to set */
usValue <<= usNPreBits;
/* Prepare a mask for setting the new bits. */
usMask = ( uint16_t )( ( 1 << ( uint16_t ) ucNBits ) - 1 );
usMask <<= usBitOffset - usByteOffset * BITS_uint8_t;
/* copy bits into temporary storage. */
usWordBuf = ucByteBuf[usByteOffset];
usWordBuf |= ucByteBuf[usByteOffset + 1] << BITS_uint8_t;
/* Zero out bit field bits and then or value bits into them. */
usWordBuf = ( uint16_t )( ( usWordBuf & ( ~usMask ) ) | usValue );
/* move bits back into storage */
ucByteBuf[usByteOffset] = ( uint8_t )( usWordBuf & 0xFF );
ucByteBuf[usByteOffset + 1] = ( uint8_t )( usWordBuf >> BITS_uint8_t );
}
uint8_t
xMBUtilGetBits( uint8_t * ucByteBuf, uint16_t usBitOffset, uint8_t ucNBits )
{
uint16_t usWordBuf;
uint16_t usMask;
uint16_t usByteOffset;
uint16_t usNPreBits;
/* Calculate byte offset for first byte containing the bit values starting
* at usBitOffset. */
usByteOffset = ( uint16_t )( ( usBitOffset ) / BITS_uint8_t );
/* How many bits precede our bits to set. */
usNPreBits = ( uint16_t )( usBitOffset - usByteOffset * BITS_uint8_t );
/* Prepare a mask for setting the new bits. */
usMask = ( uint16_t )( ( 1 << ( uint16_t ) ucNBits ) - 1 );
/* copy bits into temporary storage. */
usWordBuf = ucByteBuf[usByteOffset];
usWordBuf |= ucByteBuf[usByteOffset + 1] << BITS_uint8_t;
/* throw away unneeded bits. */
usWordBuf >>= usNPreBits;
/* mask away bits above the requested bitfield. */
usWordBuf &= usMask;
return ( 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;
}
+415
View File
@@ -0,0 +1,415 @@
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mb.c,v 1.28 2010/06/06 13:54:40 wolti Exp $
*/
/* ----------------------- System includes ----------------------------------*/
#include <nuttx/config.h>
#include <stdlib.h>
#include <string.h>
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include <apps/modbus/mb.h>
#include <apps/modbus/mbframe.h>
#include <apps/modbus/mbproto.h>
#include <apps/modbus/mbfunc.h>
#include <apps/modbus/mbport.h>
#ifdef CONFIG_MB_RTU_ENABLED
#include "mbrtu.h"
#endif
#ifdef CONFIG_MB_ASCII_ENABLED
#include "mbascii.h"
#endif
#ifdef CONFIG_MB_TCP_ENABLED
#include "mbtcp.h"
#endif
#ifndef MB_PORT_HAS_CLOSE
#define MB_PORT_HAS_CLOSE 0
#endif
/* ----------------------- Static variables ---------------------------------*/
static uint8_t ucMBAddress;
static eMBMode eMBCurrentMode;
static enum
{
STATE_ENABLED,
STATE_DISABLED,
STATE_NOT_INITIALIZED
} eMBState = STATE_NOT_INITIALIZED;
/* Functions pointer which are initialized in eMBInit( ). Depending on the
* mode (RTU or ASCII) the are set to the correct implementations.
*/
static peMBFrameSend peMBFrameSendCur;
static pvMBFrameStart pvMBFrameStartCur;
static pvMBFrameStop pvMBFrameStopCur;
static peMBFrameReceive peMBFrameReceiveCur;
static pvMBFrameClose pvMBFrameCloseCur;
/* Callback functions required by the porting layer. They are called when
* an external event has happend which includes a timeout or the reception
* or transmission of a character.
*/
bool( *pxMBFrameCBByteReceived ) ( void );
bool( *pxMBFrameCBTransmitterEmpty ) ( void );
bool( *pxMBPortCBTimerExpired ) ( void );
bool( *pxMBFrameCBReceiveFSMCur ) ( void );
bool( *pxMBFrameCBTransmitFSMCur ) ( void );
/* An array of Modbus functions handlers which associates Modbus function
* codes with implementing functions.
*/
static xMBFunctionHandler xFuncHandlers[CONFIG_MB_FUNC_HANDLERS_MAX] = {
#ifdef CONFIG_MB_FUNC_OTHER_REP_SLAVEID_ENABLED
{MB_FUNC_OTHER_REPORT_SLAVEID, eMBFuncReportSlaveID},
#endif
#ifdef CONFIG_MB_FUNC_READ_INPUT_ENABLE
{MB_FUNC_READ_INPUT_REGISTER, eMBFuncReadInputRegister},
#endif
#ifdef CONFIG_MB_FUNC_READ_HOLDING_ENABLED
{MB_FUNC_READ_HOLDING_REGISTER, eMBFuncReadHoldingRegister},
#endif
#ifdef CONFIG_MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED
{MB_FUNC_WRITE_MULTIPLE_REGISTERS, eMBFuncWriteMultipleHoldingRegister},
#endif
#ifdef CONFIG_MB_FUNC_WRITE_HOLDING_ENABLED
{MB_FUNC_WRITE_REGISTER, eMBFuncWriteHoldingRegister},
#endif
#ifdef CONFIG_MB_FUNC_READWRITE_HOLDING_ENABLED
{MB_FUNC_READWRITE_MULTIPLE_REGISTERS, eMBFuncReadWriteMultipleHoldingRegister},
#endif
#ifdef CONFIG_MB_FUNC_READ_COILS_ENABLED
{MB_FUNC_READ_COILS, eMBFuncReadCoils},
#endif
#ifdef CONFIG_MB_FUNC_WRITE_COIL_ENABLED
{MB_FUNC_WRITE_SINGLE_COIL, eMBFuncWriteCoil},
#endif
#ifdef CONFIG_MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED
{MB_FUNC_WRITE_MULTIPLE_COILS, eMBFuncWriteMultipleCoils},
#endif
#ifdef CONFIG_MB_FUNC_READ_DISCRETE_INPUTS_ENABLED
{MB_FUNC_READ_DISCRETE_INPUTS, eMBFuncReadDiscreteInputs},
#endif
};
/* ----------------------- Start implementation -----------------------------*/
eMBErrorCode
eMBInit( eMBMode eMode, uint8_t ucSlaveAddress, uint8_t ucPort, speed_t 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 )
{
#ifdef CONFIG_MB_RTU_ENABLED
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
#ifdef CONFIG_MB_ASCII_ENABLED
case MB_ASCII:
pvMBFrameStartCur = eMBASCIIStart;
pvMBFrameStopCur = eMBASCIIStop;
peMBFrameSendCur = eMBASCIISend;
peMBFrameReceiveCur = eMBASCIIReceive;
pvMBFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBPortClose : NULL;
pxMBFrameCBByteReceived = xMBASCIIReceiveFSM;
pxMBFrameCBTransmitterEmpty = xMBASCIITransmitFSM;
pxMBPortCBTimerExpired = xMBASCIITimerT1SExpired;
eStatus = eMBASCIIInit( ucMBAddress, ucPort, ulBaudRate, eParity );
break;
#endif
default:
eStatus = MB_EINVAL;
}
if( eStatus == MB_ENOERR )
{
if( !xMBPortEventInit( ) )
{
/* port dependent event module initalization failed. */
eStatus = MB_EPORTERR;
}
else
{
eMBCurrentMode = eMode;
eMBState = STATE_DISABLED;
}
}
}
return eStatus;
}
#ifdef CONFIG_MB_TCP_ENABLED
eMBErrorCode
eMBTCPInit( uint16_t 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( uint8_t ucFunctionCode, pxMBFunctionHandler pxHandler )
{
int i;
eMBErrorCode eStatus;
if( ( 0 < ucFunctionCode ) && ( ucFunctionCode <= 127 ) )
{
ENTER_CRITICAL_SECTION( );
if( pxHandler != NULL )
{
for( i = 0; i < CONFIG_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 != CONFIG_MB_FUNC_HANDLERS_MAX ) ? MB_ENOERR : MB_ENORES;
}
else
{
for( i = 0; i < CONFIG_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 uint8_t *ucMBFrame;
static uint8_t ucRcvAddress;
static uint8_t ucFunctionCode;
static 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 < CONFIG_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++] = ( uint8_t )( ucFunctionCode | MB_FUNC_ERROR );
ucMBFrame[usLength++] = eException;
}
if( ( eMBCurrentMode == MB_ASCII ) && CONFIG_MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS )
{
vMBPortTimersDelay( CONFIG_MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS );
}
eStatus = peMBFrameSendCur( ucMBAddress, ucMBFrame, usLength );
}
break;
case EV_FRAME_SENT:
break;
}
}
return MB_ENOERR;
}
+40
View File
@@ -0,0 +1,40 @@
############################################################################
# apps/modbus/nuttx/Make.defs
#
# Copyright (C) 2012 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt <gnutt@nuttx.org>
#
# 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. Neither the name NuttX nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "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
# COPYRIGHT OWNER OR CONTRIBUTORS 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.
#
############################################################################
CSRCS += portevent.c portother.c portserial.c porttimer.c
DEPPATH += --dep-path nuttx
VPATH += :nuttx
CFLAGS += ${shell $(TOPDIR)/tools/incdir.sh $(INCDIROPT) "$(CC)" $(APPDIR)/modbus/nuttx}
+77
View File
@@ -0,0 +1,77 @@
/*
* FreeModbus Libary: NuttX Port
* Based on the FreeModbus Linux port by:
*
* Copyright (C) 2006 Christian Walter <wolti@sil.at>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id: port.h,v 1.1 2006/08/01 20:58:49 wolti Exp $
*/
#ifndef __APPS_MODBUS_NUTTX_PORT_H
#define __APPS_MODBUS_NUTTX_PORT_H
#include <stdbool.h>
#include <stdint.h>
#include <assert.h>
/* ----------------------- Defines ------------------------------------------*/
#define INLINE
#define PR_BEGIN_EXTERN_C extern "C" {
#define PR_END_EXTERN_C }
#ifdef __cplusplus
PR_BEGIN_EXTERN_C
#endif
#define ENTER_CRITICAL_SECTION( ) vMBPortEnterCritical()
#define EXIT_CRITICAL_SECTION( ) vMBPortExitCritical()
#define MB_PORT_HAS_CLOSE 1
#ifndef true
# define true true
#endif
#ifndef false
# define false false
#endif
/* ----------------------- Type definitions ---------------------------------*/
typedef enum
{
MB_LOG_ERROR = 0,
MB_LOG_WARN = 1,
MB_LOG_INFO = 2,
MB_LOG_DEBUG = 3
} eMBPortLogLevel;
/* ----------------------- Function prototypes ------------------------------*/
void vMBPortEnterCritical(void);
void vMBPortExitCritical(void);
void vMBPortLog(eMBPortLogLevel eLevel, const char * szModule,
const char * szFmt, ...);
void vMBPortTimerPoll(void);
bool xMBPortSerialPoll(void);
bool xMBPortSerialSetTimeout(uint32_t dwTimeoutMs);
#ifdef __cplusplus
PR_END_EXTERN_C
#endif
#endif
+76
View File
@@ -0,0 +1,76 @@
/*
* FreeModbus Libary: NuttX Port
* Based on the FreeModbus Linux port by:
*
* Copyright (C) 2006 Christian Walter <wolti@sil.at>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id: portevent.c,v 1.1 2006/08/01 20:58:49 wolti Exp $
*/
/* ----------------------- Modbus includes ----------------------------------*/
#include <apps/modbus/mb.h>
#include <apps/modbus/mbport.h>
#include "port.h"
/* ----------------------- Variables ----------------------------------------*/
static eMBEventType eQueuedEvent;
static bool xEventInQueue;
/* ----------------------- Start implementation -----------------------------*/
bool
xMBPortEventInit( void )
{
xEventInQueue = false;
return true;
}
bool
xMBPortEventPost( eMBEventType eEvent )
{
xEventInQueue = true;
eQueuedEvent = eEvent;
return true;
}
bool
xMBPortEventGet( eMBEventType * eEvent )
{
bool xEventHappened = false;
if( xEventInQueue )
{
*eEvent = eQueuedEvent;
xEventInQueue = false;
xEventHappened = true;
}
else
{
/* Poll the serial device. The serial device timeouts if no
* characters have been received within for t3.5 during an
* active transmission or if nothing happens within a specified
* amount of time. Both timeouts are configured from the timer
* init functions.
*/
( void )xMBPortSerialPoll( );
/* Check if any of the timers have expired. */
vMBPortTimerPoll( );
}
return xEventHappened;
}
+106
View File
@@ -0,0 +1,106 @@
/*
* FreeModbus Libary: NuttX Port
* Based on the FreeModbus Linux port by:
*
* Copyright (C) 2006 Christian Walter <wolti@sil.at>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id: portother.c,v 1.1 2006/08/01 20:58:49 wolti Exp $
*/
/* ----------------------- Standard includes --------------------------------*/
#include <nuttx/config.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include <apps/modbus/mb.h>
#include <apps/modbus/mbport.h>
/* ----------------------- Defines ------------------------------------------*/
#define NELEMS(x) (sizeof((x))/sizeof((x)[0]))
/* ----------------------- Static variables ---------------------------------*/
static FILE *fLogFile = NULL;
static eMBPortLogLevel eLevelMax = MB_LOG_DEBUG;
static pthread_mutex_t xLock = PTHREAD_MUTEX_INITIALIZER;
/* ----------------------- Start implementation -----------------------------*/
void vMBPortLogLevel(eMBPortLogLevel eNewLevelMax)
{
eLevelMax = eNewLevelMax;
}
void vMBPortLogFile(FILE * fNewLogFile)
{
fLogFile = fNewLogFile;
}
void vMBPortLog(eMBPortLogLevel eLevel, const char * szModule, const char * szFmt, ...)
{
char szBuf[512];
int i;
va_list args;
FILE *fOutput = fLogFile == NULL ? stderr : fLogFile;
static const char *arszLevel2Str[] = { "ERROR", "WARN", "INFO", "DEBUG" };
i = snprintf(szBuf, NELEMS(szBuf), "%s: %s: ", arszLevel2Str[eLevel], szModule);
if (i != 0)
{
va_start(args, szFmt);
i += vsnprintf(&szBuf[i], NELEMS(szBuf) - i, szFmt, args);
va_end(args);
}
if (i != 0)
{
if (eLevel <= eLevelMax)
{
fputs(szBuf, fOutput);
}
}
}
void vMBPortEnterCritical(void)
{
int ret = pthread_mutex_lock(&xLock);
if (ret != 0)
{
vMBPortLog(MB_LOG_ERROR, "OTHER", "Locking primitive failed: %d\n", ret);
}
}
void vMBPortExitCritical(void)
{
int ret = pthread_mutex_unlock(&xLock);
if (ret != 0)
{
vMBPortLog(MB_LOG_ERROR, "OTHER", "Locking primitive failed: %d\n", ret);
}
}
+369
View File
@@ -0,0 +1,369 @@
/*
* FreeModbus Libary: NuttX Port
* Based on the FreeModbus Linux port by:
*
* Copyright (C) 2006 Christian Walter <wolti@sil.at>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id: portserial.c,v 1.3 2006/10/12 08:35:34 wolti Exp $
*/
/* ----------------------- Standard includes --------------------------------*/
#include <nuttx/config.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#ifdef CONFIG_SERIAL_TERMIOS
# include <termios.h>
#endif
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include <apps/modbus/mb.h>
#include <apps/modbus/mbport.h>
/* ----------------------- Defines -----------------------------------------*/
#ifdef CONFIG_MB_ASCII_ENABLED
#define BUF_SIZE 513 /* must hold a complete ASCII frame. */
#else
#define BUF_SIZE 256 /* must hold a complete RTU frame. */
#endif
/* ----------------------- Static variables ---------------------------------*/
static int iSerialFd = -1;
static bool bRxEnabled;
static bool bTxEnabled;
static uint32_t ulTimeoutMs;
static uint8_t ucBuffer[BUF_SIZE];
static int uiRxBufferPos;
static int uiTxBufferPos;
#ifdef CONFIG_SERIAL_TERMIOS
static struct termios xOldTIO;
#endif
/* ----------------------- Function prototypes ------------------------------*/
static bool prvbMBPortSerialRead(uint8_t *pucBuffer, uint16_t usNBytes, uint16_t *usNBytesRead);
static bool prvbMBPortSerialWrite(uint8_t *pucBuffer, uint16_t usNBytes);
/* ----------------------- Begin implementation -----------------------------*/
void vMBPortSerialEnable(bool bEnableRx, bool bEnableTx)
{
/* it is not allowed that both receiver and transmitter are enabled. */
ASSERT(!bEnableRx || !bEnableTx);
if (bEnableRx)
{
#ifdef CONFIG_SERIAL_TERMIOS
(void)tcflush(iSerialFd, TCIFLUSH);
#endif
uiRxBufferPos = 0;
bRxEnabled = true;
}
else
{
bRxEnabled = false;
}
if (bEnableTx)
{
bTxEnabled = true;
uiTxBufferPos = 0;
}
else
{
bTxEnabled = false;
}
}
bool xMBPortSerialInit(uint8_t ucPort, speed_t ulBaudRate,
uint8_t ucDataBits, eMBParity eParity)
{
char szDevice[16];
bool bStatus = true;
#ifdef CONFIG_SERIAL_TERMIOS
struct termios xNewTIO;
#endif
snprintf(szDevice, 16, "/dev/ttyS%d", ucPort);
if ((iSerialFd = open(szDevice, O_RDWR | O_NOCTTY)) < 0)
{
vMBPortLog(MB_LOG_ERROR, "SER-INIT", "Can't open serial port %s: %d\n",
szDevice, errno);
}
#ifdef CONFIG_SERIAL_TERMIOS
else if (tcgetattr(iSerialFd, &xOldTIO) != 0)
{
vMBPortLog(MB_LOG_ERROR, "SER-INIT", "Can't get settings from port %s: %d\n",
szDevice, errno);
}
else
{
bzero(&xNewTIO, sizeof(struct termios));
xNewTIO.c_iflag |= IGNBRK | INPCK;
xNewTIO.c_cflag |= CREAD | CLOCAL;
switch (eParity)
{
case MB_PAR_NONE:
break;
case MB_PAR_EVEN:
xNewTIO.c_cflag |= PARENB;
break;
case MB_PAR_ODD:
xNewTIO.c_cflag |= PARENB | PARODD;
break;
default:
bStatus = false;
}
switch (ucDataBits)
{
case 8:
xNewTIO.c_cflag |= CS8;
break;
case 7:
xNewTIO.c_cflag |= CS7;
break;
default:
bStatus = false;
}
if (bStatus)
{
/* Set the new baud. The following might be compatible with other
* OSs for the following reason.
*
* (1) In NuttX, cfset[i|o]speed always return OK so failures will
* really only be reported when tcsetattr() is called.
* (2) NuttX does not support separate input and output speeds so it
* is not necessary to call both cfsetispeed() and
* cfsetospeed(), and
* (3) In NuttX, the input value to cfiset[i|o]speed is not
* encoded, but is the absolute baud value. The following might
* not be
*/
if (cfsetispeed(&xNewTIO, ulBaudRate) != 0 /* || cfsetospeed(&xNewTIO, ulBaudRate) != 0 */)
{
vMBPortLog(MB_LOG_ERROR, "SER-INIT", "Can't set baud rate %ld for port %s: %d\n",
ulBaudRate, szDevice, errno);
}
else if (tcsetattr(iSerialFd, TCSANOW, &xNewTIO) != 0)
{
vMBPortLog(MB_LOG_ERROR, "SER-INIT", "Can't set settings for port %s: %d\n",
szDevice, errno);
}
else
{
vMBPortSerialEnable(false, false);
bStatus = true;
}
}
}
#endif
return bStatus;
}
bool xMBPortSerialSetTimeout(uint32_t ulNewTimeoutMs)
{
if (ulNewTimeoutMs > 0)
{
ulTimeoutMs = ulNewTimeoutMs;
}
else
{
ulTimeoutMs = 1;
}
return true;
}
void vMBPortClose(void)
{
if (iSerialFd != -1)
{
#ifdef CONFIG_SERIAL_TERMIOS
(void)tcsetattr(iSerialFd, TCSANOW, &xOldTIO);
#endif
(void)close(iSerialFd);
iSerialFd = -1;
}
}
bool prvbMBPortSerialRead(uint8_t *pucBuffer, uint16_t usNBytes, uint16_t *usNBytesRead)
{
bool bResult = true;
ssize_t res;
fd_set rfds;
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 50000;
FD_ZERO(&rfds);
FD_SET(iSerialFd, &rfds);
/* Wait until character received or timeout. Recover in case of an
* interrupted read system call.
*/
do
{
if (select(iSerialFd + 1, &rfds, NULL, NULL, &tv) == -1)
{
if (errno != EINTR)
{
bResult = false;
}
}
else if (FD_ISSET(iSerialFd, &rfds))
{
if ((res = read(iSerialFd, pucBuffer, usNBytes)) == -1)
{
bResult = false;
}
else
{
*usNBytesRead = (uint16_t)res;
break;
}
}
else
{
*usNBytesRead = 0;
break;
}
}
while(bResult == true);
return bResult;
}
bool prvbMBPortSerialWrite(uint8_t *pucBuffer, uint16_t usNBytes)
{
ssize_t res;
size_t left = (size_t) usNBytes;
size_t done = 0;
while(left > 0)
{
if ((res = write(iSerialFd, pucBuffer + done, left)) == -1)
{
if (errno != EINTR)
{
break;
}
/* call write again because of interrupted system call. */
continue;
}
done += res;
left -= res;
}
return left == 0 ? true : false;
}
bool
xMBPortSerialPoll()
{
bool bStatus = true;
uint16_t usBytesRead;
int i;
while(bRxEnabled)
{
if (prvbMBPortSerialRead(&ucBuffer[0], BUF_SIZE, &usBytesRead))
{
if (usBytesRead == 0)
{
/* timeout with no bytes. */
break;
}
else if (usBytesRead > 0)
{
for(i = 0; i < usBytesRead; i++)
{
/* Call the modbus stack and let him fill the buffers. */
(void)pxMBFrameCBByteReceived();
}
uiRxBufferPos = 0;
}
}
else
{
vMBPortLog(MB_LOG_ERROR, "SER-POLL", "read failed on serial device: %d\n",
errno);
bStatus = false;
}
}
if (bTxEnabled)
{
while(bTxEnabled)
{
(void)pxMBFrameCBTransmitterEmpty();
/* Call the modbus stack to let him fill the buffer. */
}
if (!prvbMBPortSerialWrite(&ucBuffer[0], uiTxBufferPos))
{
vMBPortLog(MB_LOG_ERROR, "SER-POLL", "write failed on serial device: %d\n",
errno);
bStatus = false;
}
}
return bStatus;
}
bool
xMBPortSerialPutByte(int8_t ucByte)
{
ASSERT(uiTxBufferPos < BUF_SIZE);
ucBuffer[uiTxBufferPos] = ucByte;
uiTxBufferPos++;
return true;
}
bool
xMBPortSerialGetByte(int8_t *pucByte)
{
ASSERT(uiRxBufferPos < BUF_SIZE);
*pucByte = ucBuffer[uiRxBufferPos];
uiRxBufferPos++;
return true;
}
+102
View File
@@ -0,0 +1,102 @@
/*
* FreeModbus Libary: NuttX Port
* Based on the FreeModbus Linux port by:
*
* Copyright (C) 2006 Christian Walter <wolti@sil.at>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id: porttimer.c,v 1.1 2006/08/01 20:58:50 wolti Exp $
*/
/* ----------------------- Standard includes --------------------------------*/
#include <nuttx/config.h>
#include <sys/time.h>
#include <stdlib.h>
#include <assert.h>
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include <apps/modbus/mb.h>
#include <apps/modbus/mbport.h>
/* ----------------------- Defines ------------------------------------------*/
/* ----------------------- Static variables ---------------------------------*/
uint32_t ulTimeOut;
bool bTimeoutEnable;
static struct timeval xTimeLast;
/* ----------------------- Start implementation -----------------------------*/
bool
xMBPortTimersInit( uint16_t usTim1Timerout50us )
{
ulTimeOut = usTim1Timerout50us / 20U;
if( ulTimeOut == 0 )
ulTimeOut = 1;
return xMBPortSerialSetTimeout( ulTimeOut );
}
void
xMBPortTimersClose( )
{
/* Does not use any hardware resources. */
}
void
vMBPortTimerPoll( )
{
uint32_t ulDeltaMS;
struct timeval xTimeCur;
/* Timers are called from the serial layer because we have no high
* res timer in Win32. */
if( bTimeoutEnable )
{
if( gettimeofday( &xTimeCur, NULL ) != 0 )
{
/* gettimeofday failed - retry next time. */
}
else
{
ulDeltaMS = ( xTimeCur.tv_sec - xTimeLast.tv_sec ) * 1000L +
( xTimeCur.tv_usec - xTimeLast.tv_usec ) * 1000L;
if( ulDeltaMS > ulTimeOut )
{
bTimeoutEnable = false;
( void )pxMBPortCBTimerExpired( );
}
}
}
}
void
vMBPortTimersEnable( )
{
int res = gettimeofday( &xTimeLast, NULL );
ASSERT( res == 0 );
bTimeoutEnable = true;
}
void
vMBPortTimersDisable( )
{
bTimeoutEnable = false;
}
+44
View File
@@ -0,0 +1,44 @@
############################################################################
# apps/modbus/rtu/Make.defs
#
# Copyright (C) 2012 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt <gnutt@nuttx.org>
#
# 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. Neither the name NuttX nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "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
# COPYRIGHT OWNER OR CONTRIBUTORS 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.
#
############################################################################
ifeq ($(CONFIG_MB_RTU_ENABLED),y)
CSRCS += mbcrc.c mbrtu.c
DEPPATH += --dep-path rtu
VPATH += :rtu
CFLAGS += ${shell $(TOPDIR)/tools/incdir.sh $(INCDIROPT) "$(CC)" $(APPDIR)/modbus/rtu}
endif
+98
View File
@@ -0,0 +1,98 @@
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbcrc.c,v 1.7 2007/02/18 23:50:27 wolti Exp $
*/
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
static const uint8_t aucCRCHi[] = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40
};
static const uint8_t aucCRCLo[] = {
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,
0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9,
0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF,
0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1,
0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB,
0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97,
0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E,
0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89,
0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
0x41, 0x81, 0x80, 0x40
};
uint16_t
usMBCRC16( uint8_t * pucFrame, uint16_t usLen )
{
uint8_t ucCRCHi = 0xFF;
uint8_t ucCRCLo = 0xFF;
int iIndex;
while( usLen-- )
{
iIndex = ucCRCLo ^ *( pucFrame++ );
ucCRCLo = ( uint8_t )( ucCRCHi ^ aucCRCHi[iIndex] );
ucCRCHi = aucCRCLo[iIndex];
}
return ( uint16_t )( ucCRCHi << 8 | ucCRCLo );
}
+36
View File
@@ -0,0 +1,36 @@
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbcrc.h,v 1.5 2006/12/07 22:10:34 wolti Exp $
*/
#ifndef _MB_CRC_H
#define _MB_CRC_H
uint16_t usMBCRC16( uint8_t * pucFrame, uint16_t usLen );
#endif
+357
View File
@@ -0,0 +1,357 @@
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbrtu.c,v 1.18 2007/09/12 10:15:56 wolti Exp $
*/
/* ----------------------- System includes ----------------------------------*/
#include <nuttx/config.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include <apps/modbus/mb.h>
#include <apps/modbus/mbframe.h>
#include <apps/modbus/mbport.h>
#include "mbrtu.h"
#include "mbcrc.h"
/* ----------------------- Defines ------------------------------------------*/
#define MB_SER_PDU_SIZE_MIN 4 /*!< Minimum size of a Modbus RTU frame. */
#define MB_SER_PDU_SIZE_MAX 256 /*!< Maximum size of a Modbus RTU frame. */
#define MB_SER_PDU_SIZE_CRC 2 /*!< Size of CRC field in PDU. */
#define MB_SER_PDU_ADDR_OFF 0 /*!< Offset of slave address in Ser-PDU. */
#define MB_SER_PDU_PDU_OFF 1 /*!< Offset of Modbus-PDU in Ser-PDU. */
/* ----------------------- Type definitions ---------------------------------*/
typedef enum
{
STATE_RX_INIT, /*!< Receiver is in initial state. */
STATE_RX_IDLE, /*!< Receiver is in idle state. */
STATE_RX_RCV, /*!< Frame is beeing received. */
STATE_RX_ERROR /*!< If the frame is invalid. */
} eMBRcvState;
typedef enum
{
STATE_TX_IDLE, /*!< Transmitter is in idle state. */
STATE_TX_XMIT /*!< Transmitter is in transfer state. */
} eMBSndState;
/* ----------------------- Static variables ---------------------------------*/
static volatile eMBSndState eSndState;
static volatile eMBRcvState eRcvState;
volatile uint8_t ucRTUBuf[MB_SER_PDU_SIZE_MAX];
static volatile uint8_t *pucSndBufferCur;
static volatile uint16_t usSndBufferCount;
static volatile uint16_t usRcvBufferPos;
/* ----------------------- Start implementation -----------------------------*/
eMBErrorCode
eMBRTUInit( uint8_t ucSlaveAddress, uint8_t ucPort, speed_t ulBaudRate, eMBParity eParity )
{
eMBErrorCode eStatus = MB_ENOERR;
uint32_t usTimerT35_50us;
( void )ucSlaveAddress;
ENTER_CRITICAL_SECTION( );
/* Modbus RTU uses 8 Databits. */
if( xMBPortSerialInit( ucPort, ulBaudRate, 8, eParity ) != true )
{
eStatus = MB_EPORTERR;
}
else
{
/* If baudrate > 19200 then we should use the fixed timer values
* t35 = 1750us. Otherwise t35 must be 3.5 times the character time.
*/
if( ulBaudRate > 19200 )
{
usTimerT35_50us = 35; /* 1800us. */
}
else
{
/* The timer reload value for a character is given by:
*
* ChTimeValue = Ticks_per_1s / ( Baudrate / 11 )
* = 11 * Ticks_per_1s / Baudrate
* = 220000 / Baudrate
* The reload for t3.5 is 1.5 times this value and similary
* for t3.5.
*/
usTimerT35_50us = ( 7UL * 220000UL ) / ( 2UL * ulBaudRate );
}
if( xMBPortTimersInit( ( uint16_t ) usTimerT35_50us ) != true )
{
eStatus = MB_EPORTERR;
}
}
EXIT_CRITICAL_SECTION( );
return eStatus;
}
void
eMBRTUStart( void )
{
ENTER_CRITICAL_SECTION( );
/* Initially the receiver is in the state STATE_RX_INIT. we start
* the timer and if no character is received within t3.5 we change
* to STATE_RX_IDLE. This makes sure that we delay startup of the
* modbus protocol stack until the bus is free.
*/
eRcvState = STATE_RX_INIT;
vMBPortSerialEnable( true, false );
vMBPortTimersEnable( );
EXIT_CRITICAL_SECTION( );
}
void
eMBRTUStop( void )
{
ENTER_CRITICAL_SECTION( );
vMBPortSerialEnable( false, false );
vMBPortTimersDisable( );
EXIT_CRITICAL_SECTION( );
}
eMBErrorCode
eMBRTUReceive( uint8_t * pucRcvAddress, uint8_t ** pucFrame, uint16_t * pusLength )
{
bool xFrameReceived = false;
eMBErrorCode eStatus = MB_ENOERR;
ENTER_CRITICAL_SECTION( );
ASSERT( usRcvBufferPos < MB_SER_PDU_SIZE_MAX );
/* Length and CRC check */
if( ( usRcvBufferPos >= MB_SER_PDU_SIZE_MIN )
&& ( usMBCRC16( ( uint8_t * ) ucRTUBuf, usRcvBufferPos ) == 0 ) )
{
/* Save the address field. All frames are passed to the upper layed
* and the decision if a frame is used is done there.
*/
*pucRcvAddress = ucRTUBuf[MB_SER_PDU_ADDR_OFF];
/* Total length of Modbus-PDU is Modbus-Serial-Line-PDU minus
* size of address field and CRC checksum.
*/
*pusLength = ( uint16_t )( usRcvBufferPos - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_CRC );
/* Return the start of the Modbus PDU to the caller. */
*pucFrame = ( uint8_t * ) & ucRTUBuf[MB_SER_PDU_PDU_OFF];
xFrameReceived = true;
}
else
{
eStatus = MB_EIO;
}
EXIT_CRITICAL_SECTION( );
return eStatus;
}
eMBErrorCode
eMBRTUSend( uint8_t ucSlaveAddress, const uint8_t * pucFrame, uint16_t usLength )
{
eMBErrorCode eStatus = MB_ENOERR;
uint16_t usCRC16;
ENTER_CRITICAL_SECTION( );
/* Check if the receiver is still in idle state. If not we where to
* slow with processing the received frame and the master sent another
* frame on the network. We have to abort sending the frame.
*/
if( eRcvState == STATE_RX_IDLE )
{
/* First byte before the Modbus-PDU is the slave address. */
pucSndBufferCur = ( uint8_t * ) pucFrame - 1;
usSndBufferCount = 1;
/* Now copy the Modbus-PDU into the Modbus-Serial-Line-PDU. */
pucSndBufferCur[MB_SER_PDU_ADDR_OFF] = ucSlaveAddress;
usSndBufferCount += usLength;
/* Calculate CRC16 checksum for Modbus-Serial-Line-PDU. */
usCRC16 = usMBCRC16( ( uint8_t * ) pucSndBufferCur, usSndBufferCount );
ucRTUBuf[usSndBufferCount++] = ( uint8_t )( usCRC16 & 0xFF );
ucRTUBuf[usSndBufferCount++] = ( uint8_t )( usCRC16 >> 8 );
/* Activate the transmitter. */
eSndState = STATE_TX_XMIT;
vMBPortSerialEnable( false, true );
}
else
{
eStatus = MB_EIO;
}
EXIT_CRITICAL_SECTION( );
return eStatus;
}
bool
xMBRTUReceiveFSM( void )
{
bool xTaskNeedSwitch = false;
uint8_t ucByte;
ASSERT( eSndState == STATE_TX_IDLE );
/* Always read the character. */
( void )xMBPortSerialGetByte( ( int8_t * ) & ucByte );
switch ( eRcvState )
{
/* If we have received a character in the init state we have to
* wait until the frame is finished.
*/
case STATE_RX_INIT:
vMBPortTimersEnable( );
break;
/* In the error state we wait until all characters in the
* damaged frame are transmitted.
*/
case STATE_RX_ERROR:
vMBPortTimersEnable( );
break;
/* In the idle state we wait for a new character. If a character
* is received the t1.5 and t3.5 timers are started and the
* receiver is in the state STATE_RX_RECEIVCE.
*/
case STATE_RX_IDLE:
usRcvBufferPos = 0;
ucRTUBuf[usRcvBufferPos++] = ucByte;
eRcvState = STATE_RX_RCV;
/* Enable t3.5 timers. */
vMBPortTimersEnable( );
break;
/* We are currently receiving a frame. Reset the timer after
* every character received. If more than the maximum possible
* number of bytes in a modbus frame is received the frame is
* ignored.
*/
case STATE_RX_RCV:
if( usRcvBufferPos < MB_SER_PDU_SIZE_MAX )
{
ucRTUBuf[usRcvBufferPos++] = ucByte;
}
else
{
eRcvState = STATE_RX_ERROR;
}
vMBPortTimersEnable( );
break;
}
return xTaskNeedSwitch;
}
bool
xMBRTUTransmitFSM( void )
{
bool xNeedPoll = false;
ASSERT( eRcvState == STATE_RX_IDLE );
switch ( eSndState )
{
/* We should not get a transmitter event if the transmitter is in
* idle state. */
case STATE_TX_IDLE:
/* enable receiver/disable transmitter. */
vMBPortSerialEnable( true, false );
break;
case STATE_TX_XMIT:
/* check if we are finished. */
if( usSndBufferCount != 0 )
{
xMBPortSerialPutByte( ( int8_t )*pucSndBufferCur );
pucSndBufferCur++; /* next byte in sendbuffer. */
usSndBufferCount--;
}
else
{
xNeedPoll = xMBPortEventPost( EV_FRAME_SENT );
/* Disable transmitter. This prevents another transmit buffer
* empty interrupt. */
vMBPortSerialEnable( true, false );
eSndState = STATE_TX_IDLE;
}
break;
}
return xNeedPoll;
}
bool
xMBRTUTimerT35Expired( void )
{
bool xNeedPoll = false;
switch ( eRcvState )
{
/* Timer t35 expired. Startup phase is finished. */
case STATE_RX_INIT:
xNeedPoll = xMBPortEventPost( EV_READY );
break;
/* A frame was received and t35 expired. Notify the listener that
* a new frame was received. */
case STATE_RX_RCV:
xNeedPoll = xMBPortEventPost( EV_FRAME_RECEIVED );
break;
/* An error occured while receiving the frame. */
case STATE_RX_ERROR:
break;
/* Function called in an illegal state. */
default:
ASSERT( ( eRcvState == STATE_RX_INIT ) ||
( eRcvState == STATE_RX_RCV ) || ( eRcvState == STATE_RX_ERROR ) );
}
vMBPortTimersDisable( );
eRcvState = STATE_RX_IDLE;
return xNeedPoll;
}
+51
View File
@@ -0,0 +1,51 @@
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbrtu.h,v 1.9 2006/12/07 22:10:34 wolti Exp $
*/
#ifndef _MB_RTU_H
#define _MB_RTU_H
#ifdef __cplusplus
PR_BEGIN_EXTERN_C
#endif
eMBErrorCode eMBRTUInit( uint8_t slaveAddress, uint8_t ucPort, speed_t ulBaudRate,
eMBParity eParity );
void eMBRTUStart( void );
void eMBRTUStop( void );
eMBErrorCode eMBRTUReceive( uint8_t * pucRcvAddress, uint8_t ** pucFrame, uint16_t * pusLength );
eMBErrorCode eMBRTUSend( uint8_t slaveAddress, const uint8_t * pucFrame, uint16_t usLength );
bool xMBRTUReceiveFSM( void );
bool xMBRTUTransmitFSM( void );
bool xMBRTUTimerT15Expired( void );
bool xMBRTUTimerT35Expired( void );
#ifdef __cplusplus
PR_END_EXTERN_C
#endif
#endif
+44
View File
@@ -0,0 +1,44 @@
############################################################################
# apps/modbus/tcp/Make.defs
#
# Copyright (C) 2012 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt <gnutt@nuttx.org>
#
# 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. Neither the name NuttX nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "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
# COPYRIGHT OWNER OR CONTRIBUTORS 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.
#
############################################################################
ifeq ($(CONFIG_MB_TCP_ENABLED),y)
CSRCS += mbtcp.c
DEPPATH += --dep-path tcp
VPATH += :tcp
CFLAGS += ${shell $(TOPDIR)/tools/incdir.sh $(INCDIROPT) "$(CC)" $(APPDIR)/modbus/tcp}
endif
+159
View File
@@ -0,0 +1,159 @@
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbtcp.c,v 1.3 2006/12/07 22:10:34 wolti Exp $
*/
/* ----------------------- System includes ----------------------------------*/
#include <nuttx/config.h>
#include <stdlib.h>
#include <string.h>
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include <apps/modbusmb.h>
#include <apps/modbusmbframe.h>
#include <apps/modbusmbport.h>
#include "mbtcp.h"
#ifdef CONFIG_MB_TCP_ENABLED
/* ----------------------- 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( uint16_t 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( uint8_t * pucRcvAddress, uint8_t ** ppucFrame, uint16_t * pusLength )
{
eMBErrorCode eStatus = MB_EIO;
uint8_t *pucMBTCPFrame;
uint16_t usLength;
uint16_t 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( uint8_t _unused, const uint8_t * pucFrame, uint16_t usLength )
{
eMBErrorCode eStatus = MB_ENOERR;
uint8_t *pucMBTCPFrame = ( uint8_t * ) pucFrame - MB_TCP_FUNC;
uint16_t 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
+53
View File
@@ -0,0 +1,53 @@
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006 Christian Walter <wolti@sil.at>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbtcp.h,v 1.2 2006/12/07 22:10:34 wolti Exp $
*/
#ifndef _MB_TCP_H
#define _MB_TCP_H
#ifdef __cplusplus
PR_BEGIN_EXTERN_C
#endif
/* ----------------------- Defines ------------------------------------------*/
#define MB_TCP_PSEUDO_ADDRESS 255
/* ----------------------- Function prototypes ------------------------------*/
eMBErrorCode eMBTCPDoInit( uint16_t ucTCPPort );
void eMBTCPStart( void );
void eMBTCPStop( void );
eMBErrorCode eMBTCPReceive( uint8_t * pucRcvAddress, uint8_t ** pucFrame,
uint16_t * pusLength );
eMBErrorCode eMBTCPSend( uint8_t _unused, const uint8_t * pucFrame,
uint16_t usLength );
#ifdef __cplusplus
PR_END_EXTERN_C
#endif
#endif