This example adds functionality to support basic communication in RS485 networks using Modbus protocol. This example uses FreeModbus stack and regular UART driver API to communicate in RS485 half duplex mode. Added initial support of modbus controller pure C api to access device parameters over Modbus transport. Move freemodbus stack and port files into components folder Move the modbus_controller interface into components idf folder Source files updated after review. Add modbus interface documentation docs/en/api-reference/protocols/modbus.rst porttimer.c: fix bug with timer1 selected in the Kconfig Add support of cmake system (added cmake files) Closes https://github.com/espressif/esp-idf/issues/858
125 lines
4.4 KiB
C
125 lines
4.4 KiB
C
/*
|
|
* FreeRTOS Modbus Libary: A Modbus serial implementation for FreeRTOS
|
|
* Copyright (C) 2006 Christian Walter <wolti@sil.at>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
|
|
|
|
/* ----------------------- System includes ----------------------------------*/
|
|
#include "stdlib.h"
|
|
#include "string.h"
|
|
|
|
/* ----------------------- Platform includes --------------------------------*/
|
|
#include "port.h"
|
|
|
|
/* ----------------------- Modbus includes ----------------------------------*/
|
|
#include "mb.h"
|
|
#include "mbframe.h"
|
|
#include "mbproto.h"
|
|
#include "mbconfig.h"
|
|
|
|
/* ----------------------- Defines ------------------------------------------*/
|
|
#define MB_PDU_FUNC_READ_ADDR_OFF ( MB_PDU_DATA_OFF )
|
|
#define MB_PDU_FUNC_READ_DISCCNT_OFF ( MB_PDU_DATA_OFF + 2 )
|
|
#define MB_PDU_FUNC_READ_SIZE ( 4 )
|
|
#define MB_PDU_FUNC_READ_DISCCNT_MAX ( 0x07D0 )
|
|
|
|
/* ----------------------- Static functions ---------------------------------*/
|
|
eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
|
|
|
|
/* ----------------------- Start implementation -----------------------------*/
|
|
|
|
#if MB_FUNC_READ_COILS_ENABLED > 0
|
|
|
|
eMBException
|
|
eMBFuncReadDiscreteInputs( UCHAR * pucFrame, USHORT * usLen )
|
|
{
|
|
USHORT usRegAddress;
|
|
USHORT usDiscreteCnt;
|
|
UCHAR ucNBytes;
|
|
UCHAR *pucFrameCur;
|
|
|
|
eMBException eStatus = MB_EX_NONE;
|
|
eMBErrorCode eRegStatus;
|
|
|
|
if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
|
|
{
|
|
usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
|
|
usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
|
|
usRegAddress++;
|
|
|
|
usDiscreteCnt = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_DISCCNT_OFF] << 8 );
|
|
usDiscreteCnt |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_DISCCNT_OFF + 1] );
|
|
|
|
/* Check if the number of registers to read is valid. If not
|
|
* return Modbus illegal data value exception.
|
|
*/
|
|
if( ( usDiscreteCnt >= 1 ) &&
|
|
( usDiscreteCnt < MB_PDU_FUNC_READ_DISCCNT_MAX ) )
|
|
{
|
|
/* Set the current PDU data pointer to the beginning. */
|
|
pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
|
|
*usLen = MB_PDU_FUNC_OFF;
|
|
|
|
/* First byte contains the function code. */
|
|
*pucFrameCur++ = MB_FUNC_READ_DISCRETE_INPUTS;
|
|
*usLen += 1;
|
|
|
|
/* Test if the quantity of coils is a multiple of 8. If not last
|
|
* byte is only partially field with unused coils set to zero. */
|
|
if( ( usDiscreteCnt & 0x0007 ) != 0 )
|
|
{
|
|
ucNBytes = ( UCHAR ) ( usDiscreteCnt / 8 + 1 );
|
|
}
|
|
else
|
|
{
|
|
ucNBytes = ( UCHAR ) ( usDiscreteCnt / 8 );
|
|
}
|
|
*pucFrameCur++ = ucNBytes;
|
|
*usLen += 1;
|
|
|
|
eRegStatus =
|
|
eMBRegDiscreteCB( pucFrameCur, usRegAddress, usDiscreteCnt );
|
|
|
|
/* If an error occured convert it into a Modbus exception. */
|
|
if( eRegStatus != MB_ENOERR )
|
|
{
|
|
eStatus = prveMBError2Exception( eRegStatus );
|
|
}
|
|
else
|
|
{
|
|
/* The response contains the function code, the starting address
|
|
* and the quantity of registers. We reuse the old values in the
|
|
* buffer because they are still valid. */
|
|
*usLen += ucNBytes;;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Can't be a valid read coil register request because the length
|
|
* is incorrect. */
|
|
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
|
|
}
|
|
return eStatus;
|
|
}
|
|
|
|
#endif
|