Modbus Master is missing many files and doesn't compile at all. I'm attaching diff with my implementation. More details in https://groups.yahoo.com/neo/groups/nuttx/conversations/topics/13734
This commit is contained in:
parent
0b810c5339
commit
e3eacfe985
@ -63,7 +63,7 @@ typedef enum
|
||||
EV_MASTER_EXECUTE = 1<<2, /* Execute function. */
|
||||
EV_MASTER_FRAME_SENT = 1<<3, /* Frame sent. */
|
||||
EV_MASTER_ERROR_PROCESS = 1<<4, /* Frame error process. */
|
||||
EV_MASTER_PROCESS_SUCESS = 1<<5, /* Request process success. */
|
||||
EV_MASTER_PROCESS_SUCCESS = 1<<5, /* Request process success. */
|
||||
EV_MASTER_ERROR_RESPOND_TIMEOUT = 1<<6, /* Request respond timeout. */
|
||||
EV_MASTER_ERROR_RECEIVE_DATA = 1<<7, /* Request receive data error. */
|
||||
EV_MASTER_ERROR_EXECUTE_FUNCTION = 1<<8 /* Request execute function error. */
|
||||
@ -171,7 +171,7 @@ void vMBMasterErrorCBReceiveData(uint8_t ucDestAddress, const uint8_t *pucPDUDat
|
||||
uint16_t ucPDULength);
|
||||
void vMBMasterErrorCBExecuteFunction(uint8_t ucDestAddress, const uint8_t *pucPDUData,
|
||||
uint16_t ucPDULength);
|
||||
void vMBMasterCBRequestScuuess(void);
|
||||
void vMBMasterCBRequestSuccess(void);
|
||||
|
||||
#ifdef CONFIG_MB_TCP_ENABLED
|
||||
/* TCP port function */
|
||||
|
136
modbus/Kconfig
136
modbus/Kconfig
@ -4,31 +4,35 @@
|
||||
#
|
||||
|
||||
menu "FreeModBus"
|
||||
|
||||
config MODBUS
|
||||
bool "Modbus support via FreeModBus"
|
||||
bool "Modbus support using FreeModbus"
|
||||
default n
|
||||
|
||||
if MODBUS
|
||||
|
||||
config MB_FUNC_HANDLERS_MAX
|
||||
int "Maximum number of Modbus functions"
|
||||
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 MODBUS_SLAVE
|
||||
bool "Modbus slave support via FreeModBus"
|
||||
default n
|
||||
|
||||
if MODBUS_SLAVE
|
||||
config MB_ASCII_ENABLED
|
||||
bool "Modbus ASCII support"
|
||||
default y
|
||||
|
||||
config MB_ASCII_MASTER
|
||||
bool "Modbus ASCII master"
|
||||
default n
|
||||
depends on MB_ASCII_ENABLED
|
||||
|
||||
config MB_RTU_ENABLED
|
||||
bool "Modbus RTU support"
|
||||
default y
|
||||
|
||||
config MB_RTU_MASTER
|
||||
bool "Modbus RTU master"
|
||||
default n
|
||||
depends on MB_RTU_ENABLED
|
||||
|
||||
config MB_TCP_ENABLED
|
||||
bool "Modbus TCP support"
|
||||
default y
|
||||
@ -68,16 +72,6 @@ config MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS
|
||||
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"
|
||||
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
|
||||
@ -150,6 +144,32 @@ config MB_FUNC_READWRITE_HOLDING_ENABLED
|
||||
---help---
|
||||
If the Read/Write Multiple Registers function should be enabled.
|
||||
|
||||
endif # MODBUS_SLAVE
|
||||
|
||||
config MODBUS_MASTER
|
||||
bool "Modbus Master support via FreeModBus"
|
||||
default n
|
||||
|
||||
if MODBUS_MASTER
|
||||
|
||||
if 0
|
||||
config MB_ASCII_MASTER
|
||||
bool "Modbus ASCII master"
|
||||
default n
|
||||
endif
|
||||
|
||||
config MB_RTU_MASTER
|
||||
bool "Modbus RTU master"
|
||||
default n
|
||||
|
||||
config MB_PORT_HAS_CLOSE
|
||||
bool "Platform close callbacks"
|
||||
default n
|
||||
---help---
|
||||
A port which wants to get an callback must select
|
||||
CONFIG_MB_HAS_CLOSE and provide vMBMasterPortClose() as
|
||||
as pvMBMasterFrameCloseCur() (if CONFIG_MB_RTU_MASTER)
|
||||
|
||||
if MB_ASCII_MASTER || MB_RTU_MASTER
|
||||
|
||||
config MB_MASTER_TOTAL_SLAVE_NUM
|
||||
@ -159,6 +179,78 @@ config MB_MASTER_TOTAL_SLAVE_NUM
|
||||
The total slaves in Modbus Master system. Default 16.
|
||||
NOTE: The slave ID must be continuous from 1.
|
||||
|
||||
config MB_MASTER_DELAY_MS_CONVERT
|
||||
int "Convert Delay value"
|
||||
default 200
|
||||
---help---
|
||||
When master sends a broadcast frame, it should allow slaves to process
|
||||
current frame before sending new frame. New frame will be send only
|
||||
after Convert Delay time duration.
|
||||
|
||||
config MB_MASTER_TIMEOUT_MS_RESPOND
|
||||
int "Respond timeout value"
|
||||
default 1000
|
||||
---help---
|
||||
When master sends frame, which is not broadcast, it should wait for
|
||||
given time duration for slave response. If slave doesn't respond
|
||||
during give time period, the master will process timeout
|
||||
error and only then it will be able to send new frame.
|
||||
|
||||
config MB_MASTER_FUNC_READ_INPUT_ENABLED
|
||||
bool "Read Input Registers function"
|
||||
default y
|
||||
---help---
|
||||
If the Read Input Registers function should be enabled.
|
||||
|
||||
config MB_MASTER_FUNC_READ_HOLDING_ENABLED
|
||||
bool "Read Holding Registers function"
|
||||
default y
|
||||
---help---
|
||||
If the Read Holding Registers function should be enabled.
|
||||
|
||||
config MB_MASTER_FUNC_WRITE_HOLDING_ENABLED
|
||||
bool "Write Single Register function"
|
||||
default y
|
||||
---help---
|
||||
If the Write Single Register function should be enabled.
|
||||
|
||||
config MB_MASTER_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED
|
||||
bool "Write Multiple registers function"
|
||||
default y
|
||||
---help---
|
||||
If the Write Multiple registers function should be enabled.
|
||||
|
||||
config MB_MASTER_FUNC_READ_COILS_ENABLED
|
||||
bool "Read Coils function"
|
||||
default y
|
||||
---help---
|
||||
If the Read Coils function should be enabled.
|
||||
|
||||
config MB_MASTER_FUNC_WRITE_COIL_ENABLED
|
||||
bool "Write Coils function"
|
||||
default y
|
||||
---help---
|
||||
If the Write Coils function should be enabled.
|
||||
|
||||
config MB_MASTER_FUNC_WRITE_MULTIPLE_COILS_ENABLED
|
||||
bool "Write Multiple Coils function"
|
||||
default y
|
||||
---help---
|
||||
If the Write Multiple Coils function should be enabled.
|
||||
|
||||
config MB_MASTER_FUNC_READ_DISCRETE_INPUTS_ENABLED
|
||||
bool "Read Discrete Inputs function"
|
||||
default y
|
||||
---help---
|
||||
If the Read Discrete Inputs function should be enabled.
|
||||
|
||||
config MB_MASTER_FUNC_READWRITE_HOLDING_ENABLED
|
||||
bool "Read/Write Multiple Registers function"
|
||||
default y
|
||||
---help---
|
||||
If the Read/Write Multiple Registers function should be enabled.
|
||||
|
||||
endif # MB_ASCII_MASTER || MB_RTU_MASTER
|
||||
endif # MODBUS_MASTER
|
||||
endif # MODBUS
|
||||
endmenu # FreeModBus
|
||||
|
@ -44,7 +44,14 @@ CSRCS =
|
||||
|
||||
ifeq ($(CONFIG_MODBUS),y)
|
||||
|
||||
ifeq ($(CONFIG_MODBUS_SLAVE),y)
|
||||
CSRCS += mb.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_MB_RTU_MASTER),y)
|
||||
CSRCS += mb_m.c
|
||||
endif
|
||||
|
||||
DEPPATH = --dep-path .
|
||||
VPATH = .
|
||||
|
||||
|
@ -83,7 +83,7 @@ eMBException prveMBError2Exception(eMBErrorCode eErrorCode);
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_RTU_ASCII_MASTER) || defined(CONFIG_MB_ASCII_MASTER)
|
||||
#if defined(CONFIG_MB_RTU_MASTER) || defined(CONFIG_MB_ASCII_MASTER)
|
||||
|
||||
/****************************************************************************
|
||||
* Description:
|
||||
@ -100,7 +100,7 @@ eMBException prveMBError2Exception(eMBErrorCode eErrorCode);
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_MB_FUNC_READ_COILS_ENABLED
|
||||
#ifdef CONFIG_MB_MASTER_FUNC_READ_COILS_ENABLED
|
||||
eMBMasterReqErrCode eMBMasterReqReadCoils(uint8_t ucSndAddr,
|
||||
uint16_t usCoilAddr,
|
||||
uint16_t usNCoils,
|
||||
@ -230,7 +230,7 @@ eMBException eMBMasterFuncReadCoils(uint8_t *pucFrame, uint16_t *usLen)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_MB_FUNC_WRITE_COIL_ENABLED
|
||||
#ifdef CONFIG_MB_MASTER_FUNC_WRITE_COIL_ENABLED
|
||||
eMBMasterReqErrCode eMBMasterReqWriteCoil(uint8_t ucSndAddr,
|
||||
uint16_t usCoilAddr,
|
||||
uint16_t usCoilData,
|
||||
@ -342,7 +342,7 @@ eMBException eMBMasterFuncWriteCoil(uint8_t *pucFrame, uint16_t *usLen)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED
|
||||
#ifdef CONFIG_MB_MASTER_FUNC_WRITE_MULTIPLE_COILS_ENABLED
|
||||
eMBMasterReqErrCode eMBMasterReqWriteMultipleCoils(uint8_t ucSndAddr,
|
||||
uint16_t usCoilAddr,
|
||||
uint16_t usNCoils,
|
||||
|
@ -65,7 +65,7 @@ eMBException prveMBError2Exception(eMBErrorCode eErrorCode);
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_RTU_ASCII_MASTER) || defined(CONFIG_MB_ASCII_MASTER)
|
||||
#if defined(CONFIG_MB_RTU_MASTER) || defined(CONFIG_MB_ASCII_MASTER)
|
||||
|
||||
/****************************************************************************
|
||||
* Description:
|
||||
@ -82,7 +82,7 @@ eMBException prveMBError2Exception(eMBErrorCode eErrorCode);
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_MB_FUNC_READ_DISCRETE_INPUTS_ENABLED
|
||||
#ifdef CONFIG_MB_MASTER_FUNC_READ_DISCRETE_INPUTS_ENABLED
|
||||
eMBMasterReqErrCode eMBMasterReqReadDiscreteInputs(uint8_t ucSndAddr,
|
||||
uint16_t usDiscreteAddr,
|
||||
uint16_t usNDiscreteIn,
|
||||
|
@ -94,7 +94,7 @@ eMBException prveMBError2Exception(eMBErrorCode eErrorCode);
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_RTU_ASCII_MASTER) || defined(CONFIG_MB_ASCII_MASTER)
|
||||
#if defined(CONFIG_MB_RTU_MASTER) || defined(CONFIG_MB_ASCII_MASTER)
|
||||
|
||||
/****************************************************************************
|
||||
* Description:
|
||||
@ -111,7 +111,7 @@ eMBException prveMBError2Exception(eMBErrorCode eErrorCode);
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_MB_FUNC_WRITE_HOLDING_ENABLED
|
||||
#ifdef CONFIG_MB_MASTER_FUNC_WRITE_HOLDING_ENABLED
|
||||
eMBMasterReqErrCode eMBMasterReqWriteHoldingRegister(uint8_t ucSndAddr,
|
||||
uint16_t usRegAddr,
|
||||
uint16_t usRegData,
|
||||
@ -195,7 +195,7 @@ eMBException eMBMasterFuncWriteHoldingRegister(uint8_t *pucFrame,
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED
|
||||
#ifdef CONFIG_MB_MASTER_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqWriteMultipleHoldingRegister(uint8_t ucSndAddr,
|
||||
uint16_t usRegAddr,
|
||||
@ -313,7 +313,7 @@ eMBException eMBMasterFuncWriteMultipleHoldingRegister(uint8_t *pucFrame,
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_MB_FUNC_READ_HOLDING_ENABLED
|
||||
#ifdef CONFIG_MB_MASTER_FUNC_READ_HOLDING_ENABLED
|
||||
eMBMasterReqErrCode eMBMasterReqReadHoldingRegister(uint8_t ucSndAddr,
|
||||
uint16_t usRegAddr,
|
||||
uint16_t usNRegs,
|
||||
@ -429,7 +429,7 @@ eMBException eMBMasterFuncReadHoldingRegister(uint8_t *pucFrame,
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_MB_FUNC_READWRITE_HOLDING_ENABLED
|
||||
#ifdef CONFIG_MB_MASTER_FUNC_READWRITE_HOLDING_ENABLED
|
||||
eMBMasterReqErrCode
|
||||
eMBMasterReqReadWriteMultipleHoldingRegister(uint8_t ucSndAddr,
|
||||
uint16_t usReadRegAddr,
|
||||
|
@ -67,7 +67,7 @@ eMBException prveMBError2Exception(eMBErrorCode eErrorCode);
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_RTU_ASCII_MASTER) || defined(CONFIG_MB_ASCII_MASTER)
|
||||
#if defined(CONFIG_MB_RTU_MASTER) || defined(CONFIG_MB_ASCII_MASTER)
|
||||
|
||||
/****************************************************************************
|
||||
* Description:
|
||||
@ -84,7 +84,7 @@ eMBException prveMBError2Exception(eMBErrorCode eErrorCode);
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_MB_FUNC_READ_INPUT_ENABLED)
|
||||
#if defined(CONFIG_MB_MASTER_FUNC_READ_INPUT_ENABLED)
|
||||
eMBMasterReqErrCode eMBMasterReqReadInputRegister(uint8_t ucSndAddr,
|
||||
uint16_t usRegAddr,
|
||||
uint16_t usNRegs,
|
||||
|
480
modbus/mb_m.c
Normal file
480
modbus/mb_m.c
Normal file
@ -0,0 +1,480 @@
|
||||
/****************************************************************************
|
||||
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
*
|
||||
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "port.h"
|
||||
|
||||
#include "modbus/mb.h"
|
||||
#include "modbus/mb_m.h"
|
||||
#include "modbus/mbframe.h"
|
||||
#include "modbus/mbproto.h"
|
||||
#include "modbus/mbfunc.h"
|
||||
|
||||
#include "modbus/mbport.h"
|
||||
|
||||
#ifdef CONFIG_MB_RTU_MASTER
|
||||
# include "mbrtu_m.h"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MB_ASCII_MASTER
|
||||
# include "mbascii.h"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MB_TCP_MASTER
|
||||
# include "mbtcp.h"
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_MB_RTU_MASTER) || defined(CONFIG_MB_ASCII_MASTER)
|
||||
|
||||
#ifndef CONFIG_MB_PORT_HAS_CLOSE
|
||||
# define MB_PORT_HAS_CLOSE 0
|
||||
#else
|
||||
# define MB_PORT_HAS_CLOSE 1
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static uint8_t ucMBMasterDestAddress;
|
||||
static bool xMBRunInMasterMode = false;
|
||||
static eMBMasterErrorEventType eMBMasterCurErrorType;
|
||||
|
||||
static enum
|
||||
{
|
||||
STATE_ENABLED,
|
||||
STATE_DISABLED,
|
||||
STATE_NOT_INITIALIZED
|
||||
} eMBState = STATE_NOT_INITIALIZED;
|
||||
|
||||
/* Functions pointer which are initialized in eMBInit( ). Depending on the
|
||||
* mode (RTU or ASCII) the are set to the correct implementations.
|
||||
* Using for Modbus Master,Add by Armink 20130813
|
||||
*/
|
||||
|
||||
static peMBFrameSend peMBMasterFrameSendCur;
|
||||
static pvMBFrameStart pvMBMasterFrameStartCur;
|
||||
static pvMBFrameStop pvMBMasterFrameStopCur;
|
||||
static peMBFrameReceive peMBMasterFrameReceiveCur;
|
||||
static pvMBFrameClose pvMBMasterFrameCloseCur;
|
||||
|
||||
/* Callback functions required by the porting layer. They are called when
|
||||
* an external event has happend which includes a timeout or the reception
|
||||
* or transmission of a character.
|
||||
* Using for Modbus Master,Add by Armink 20130813
|
||||
*/
|
||||
|
||||
bool(*pxMBMasterFrameCBByteReceived) (void);
|
||||
bool(*pxMBMasterFrameCBTransmitterEmpty) (void);
|
||||
bool(*pxMBMasterPortCBTimerExpired) (void);
|
||||
|
||||
bool(*pxMBMasterFrameCBReceiveFSMCur) (void);
|
||||
bool(*pxMBMasterFrameCBTransmitFSMCur) (void);
|
||||
|
||||
/* An array of Modbus functions handlers which associates Modbus function
|
||||
* codes with implementing functions.
|
||||
*/
|
||||
|
||||
static xMBFunctionHandler xMasterFuncHandlers[CONFIG_MB_FUNC_HANDLERS_MAX] = {
|
||||
#ifdef CONFIG_MB_FUNC_OTHER_REP_SLAVEID_ENABLED
|
||||
|
||||
/* TODO Add Master function define */
|
||||
|
||||
{MB_FUNC_OTHER_REPORT_SLAVEID, eMBFuncReportSlaveID},
|
||||
#endif
|
||||
#ifdef CONFIG_MB_MASTER_FUNC_READ_INPUT_ENABLED
|
||||
{MB_FUNC_READ_INPUT_REGISTER, eMBMasterFuncReadInputRegister},
|
||||
#endif
|
||||
#ifdef CONFIG_MB_MASTER_FUNC_READ_HOLDING_ENABLED
|
||||
{MB_FUNC_READ_HOLDING_REGISTER, eMBMasterFuncReadHoldingRegister},
|
||||
#endif
|
||||
#ifdef CONFIG_MB_MASTER_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED
|
||||
{MB_FUNC_WRITE_MULTIPLE_REGISTERS, eMBMasterFuncWriteMultipleHoldingRegister},
|
||||
#endif
|
||||
#ifdef CONFIG_MB_MASTER_FUNC_WRITE_HOLDING_ENABLED
|
||||
{MB_FUNC_WRITE_REGISTER, eMBMasterFuncWriteHoldingRegister},
|
||||
#endif
|
||||
#ifdef CONFIG_MB_MASTER_FUNC_READWRITE_HOLDING_ENABLED
|
||||
{MB_FUNC_READWRITE_MULTIPLE_REGISTERS,
|
||||
eMBMasterFuncReadWriteMultipleHoldingRegister},
|
||||
#endif
|
||||
#ifdef CONFIG_MB_MASTER_FUNC_READ_COILS_ENABLED
|
||||
{MB_FUNC_READ_COILS, eMBMasterFuncReadCoils},
|
||||
#endif
|
||||
#ifdef CONFIG_MB_MASTER_FUNC_WRITE_COIL_ENABLED
|
||||
{MB_FUNC_WRITE_SINGLE_COIL, eMBMasterFuncWriteCoil},
|
||||
#endif
|
||||
#ifdef CONFIG_MB_MASTER_FUNC_WRITE_MULTIPLE_COILS_ENABLED
|
||||
{MB_FUNC_WRITE_MULTIPLE_COILS, eMBMasterFuncWriteMultipleCoils},
|
||||
#endif
|
||||
#ifdef CONFIG_MB_MASTER_FUNC_READ_DISCRETE_INPUTS_ENABLED
|
||||
{MB_FUNC_READ_DISCRETE_INPUTS, eMBMasterFuncReadDiscreteInputs},
|
||||
#endif
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
eMBErrorCode eMBMasterInit(eMBMode eMode, uint8_t ucPort,
|
||||
speed_t ulBaudRate, eMBParity eParity)
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
|
||||
switch (eMode)
|
||||
{
|
||||
#ifdef CONFIG_MB_RTU_MASTER
|
||||
case MB_RTU:
|
||||
pvMBMasterFrameStartCur = eMBMasterRTUStart;
|
||||
pvMBMasterFrameStopCur = eMBMasterRTUStop;
|
||||
peMBMasterFrameSendCur = eMBMasterRTUSend;
|
||||
peMBMasterFrameReceiveCur = eMBMasterRTUReceive;
|
||||
pvMBMasterFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBMasterPortClose : NULL;
|
||||
pxMBMasterFrameCBByteReceived = xMBMasterRTUReceiveFSM;
|
||||
pxMBMasterFrameCBTransmitterEmpty = xMBMasterRTUTransmitFSM;
|
||||
pxMBMasterPortCBTimerExpired = xMBMasterRTUTimerExpired;
|
||||
|
||||
eStatus = eMBMasterRTUInit(ucPort, ulBaudRate, eParity);
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_MB_ASCII_MASTER
|
||||
case MB_ASCII:
|
||||
pvMBMasterFrameStartCur = eMBMasterASCIIStart;
|
||||
pvMBMasterFrameStopCur = eMBMasterASCIIStop;
|
||||
peMBMasterFrameSendCur = eMBMasterASCIISend;
|
||||
peMBMasterFrameReceiveCur = eMBMasterASCIIReceive;
|
||||
pvMBMasterFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBMasterPortClose : NULL;
|
||||
pxMBMasterFrameCBByteReceived = xMBMasterASCIIReceiveFSM;
|
||||
pxMBMasterFrameCBTransmitterEmpty = xMBMasterASCIITransmitFSM;
|
||||
pxMBMasterPortCBTimerExpired = xMBMasterASCIITimerT1SExpired;
|
||||
|
||||
eStatus = eMBMasterASCIIInit(ucPort, ulBaudRate, eParity);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
eStatus = MB_EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (eStatus == MB_ENOERR)
|
||||
{
|
||||
if (!xMBMasterPortEventInit())
|
||||
{
|
||||
/* Port dependent event module initalization failed. */
|
||||
|
||||
eStatus = MB_EPORTERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
eMBState = STATE_DISABLED;
|
||||
}
|
||||
|
||||
/* Initialize the OS resource for modbus master. */
|
||||
|
||||
vMBMasterOsResInit();
|
||||
}
|
||||
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
eMBErrorCode eMBMasterClose(void)
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
|
||||
if (eMBState == STATE_DISABLED)
|
||||
{
|
||||
if (pvMBMasterFrameCloseCur != NULL)
|
||||
{
|
||||
pvMBMasterFrameCloseCur();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EILLSTATE;
|
||||
}
|
||||
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
eMBErrorCode eMBMasterEnable(void)
|
||||
{
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
|
||||
if (eMBState == STATE_DISABLED)
|
||||
{
|
||||
/* Activate the protocol stack. */
|
||||
|
||||
pvMBMasterFrameStartCur();
|
||||
eMBState = STATE_ENABLED;
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EILLSTATE;
|
||||
}
|
||||
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
eMBErrorCode eMBMasterDisable(void)
|
||||
{
|
||||
eMBErrorCode eStatus;
|
||||
|
||||
if (eMBState == STATE_ENABLED)
|
||||
{
|
||||
pvMBMasterFrameStopCur();
|
||||
eMBState = STATE_DISABLED;
|
||||
eStatus = MB_ENOERR;
|
||||
}
|
||||
else if (eMBState == STATE_DISABLED)
|
||||
{
|
||||
eStatus = MB_ENOERR;
|
||||
}
|
||||
else
|
||||
{
|
||||
eStatus = MB_EILLSTATE;
|
||||
}
|
||||
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
eMBErrorCode eMBMasterPoll(void)
|
||||
{
|
||||
static uint8_t *ucMBFrame;
|
||||
static uint8_t ucRcvAddress;
|
||||
static uint8_t ucFunctionCode;
|
||||
static uint16_t usLength;
|
||||
static eMBException eException;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
eMBMasterEventType eEvent;
|
||||
eMBMasterErrorEventType errorType;
|
||||
|
||||
/* 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 (xMBMasterPortEventGet(&eEvent) == true)
|
||||
{
|
||||
switch (eEvent)
|
||||
{
|
||||
case EV_MASTER_READY:
|
||||
break;
|
||||
|
||||
case EV_MASTER_FRAME_RECEIVED:
|
||||
eStatus =
|
||||
peMBMasterFrameReceiveCur(&ucRcvAddress, &ucMBFrame, &usLength);
|
||||
|
||||
/* Check if the frame is for us. If not, send an error process event. */
|
||||
|
||||
if ((eStatus == MB_ENOERR) &&
|
||||
(ucRcvAddress == ucMBMasterGetDestAddress()))
|
||||
{
|
||||
(void)xMBMasterPortEventPost(EV_MASTER_EXECUTE);
|
||||
}
|
||||
else
|
||||
{
|
||||
vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA);
|
||||
(void)xMBMasterPortEventPost(EV_MASTER_ERROR_PROCESS);
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_MASTER_EXECUTE:
|
||||
ucFunctionCode = ucMBFrame[MB_PDU_FUNC_OFF];
|
||||
eException = MB_EX_ILLEGAL_FUNCTION;
|
||||
|
||||
/* If receive frame has exception. The receive function code highest
|
||||
* bit is 1.
|
||||
*/
|
||||
|
||||
if (ucFunctionCode >> 7)
|
||||
{
|
||||
eException = (eMBException) ucMBFrame[MB_PDU_DATA_OFF];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < CONFIG_MB_FUNC_HANDLERS_MAX; i++)
|
||||
{
|
||||
/* No more function handlers registered. Abort. */
|
||||
|
||||
if (xMasterFuncHandlers[i].ucFunctionCode == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (xMasterFuncHandlers[i].ucFunctionCode ==
|
||||
ucFunctionCode)
|
||||
{
|
||||
vMBMasterSetCBRunInMasterMode(true);
|
||||
|
||||
/* If master request is broadcast, the master need
|
||||
* execute function for all slave. */
|
||||
|
||||
if (xMBMasterRequestIsBroadcast())
|
||||
{
|
||||
usLength = usMBMasterGetPDUSndLength();
|
||||
for (j = 1; j <= CONFIG_MB_MASTER_TOTAL_SLAVE_NUM;
|
||||
j++)
|
||||
{
|
||||
vMBMasterSetDestAddress(j);
|
||||
eException =
|
||||
xMasterFuncHandlers[i].pxHandler(ucMBFrame,
|
||||
&usLength);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eException =
|
||||
xMasterFuncHandlers[i].pxHandler(ucMBFrame,
|
||||
&usLength);
|
||||
}
|
||||
|
||||
vMBMasterSetCBRunInMasterMode(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If master has exception, Master will send error process. Otherwise
|
||||
* the Master is idle.
|
||||
*/
|
||||
|
||||
if (eException != MB_EX_NONE)
|
||||
{
|
||||
vMBMasterSetErrorType(EV_ERROR_EXECUTE_FUNCTION);
|
||||
(void)xMBMasterPortEventPost(EV_MASTER_ERROR_PROCESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
vMBMasterCBRequestSuccess();
|
||||
vMBMasterRunResRelease();
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_MASTER_FRAME_SENT:
|
||||
|
||||
/* Master is busy now. */
|
||||
|
||||
vMBMasterGetPDUSndBuf(&ucMBFrame);
|
||||
eStatus =
|
||||
peMBMasterFrameSendCur(ucMBMasterGetDestAddress(), ucMBFrame,
|
||||
usMBMasterGetPDUSndLength());
|
||||
break;
|
||||
|
||||
case EV_MASTER_ERROR_PROCESS:
|
||||
|
||||
/* Execute specified error process callback function. */
|
||||
|
||||
errorType = eMBMasterGetErrorType();
|
||||
vMBMasterGetPDUSndBuf(&ucMBFrame);
|
||||
switch (errorType)
|
||||
{
|
||||
case EV_ERROR_RESPOND_TIMEOUT:
|
||||
vMBMasterErrorCBRespondTimeout(ucMBMasterGetDestAddress(),
|
||||
ucMBFrame,
|
||||
usMBMasterGetPDUSndLength());
|
||||
break;
|
||||
case EV_ERROR_RECEIVE_DATA:
|
||||
vMBMasterErrorCBReceiveData(ucMBMasterGetDestAddress(),
|
||||
ucMBFrame,
|
||||
usMBMasterGetPDUSndLength());
|
||||
break;
|
||||
case EV_ERROR_EXECUTE_FUNCTION:
|
||||
vMBMasterErrorCBExecuteFunction(ucMBMasterGetDestAddress(),
|
||||
ucMBFrame,
|
||||
usMBMasterGetPDUSndLength());
|
||||
break;
|
||||
}
|
||||
|
||||
vMBMasterRunResRelease();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return MB_ENOERR;
|
||||
}
|
||||
|
||||
/* Get whether the Modbus Master is run in master mode.*/
|
||||
|
||||
bool xMBMasterGetCBRunInMasterMode(void)
|
||||
{
|
||||
return xMBRunInMasterMode;
|
||||
}
|
||||
|
||||
/* Set whether the Modbus Master is run in master mode.*/
|
||||
|
||||
void vMBMasterSetCBRunInMasterMode(bool IsMasterMode)
|
||||
{
|
||||
xMBRunInMasterMode = IsMasterMode;
|
||||
}
|
||||
|
||||
/* Get Modbus Master send destination address. */
|
||||
|
||||
uint8_t ucMBMasterGetDestAddress(void)
|
||||
{
|
||||
return ucMBMasterDestAddress;
|
||||
}
|
||||
|
||||
/* Set Modbus Master send destination address. */
|
||||
|
||||
void vMBMasterSetDestAddress(uint8_t Address)
|
||||
{
|
||||
ucMBMasterDestAddress = Address;
|
||||
}
|
||||
|
||||
/* Get Modbus Master current error event type. */
|
||||
|
||||
eMBMasterErrorEventType eMBMasterGetErrorType(void)
|
||||
{
|
||||
return eMBMasterCurErrorType;
|
||||
}
|
||||
|
||||
/* Set Modbus Master current error event type. */
|
||||
|
||||
void vMBMasterSetErrorType(eMBMasterErrorEventType errorType)
|
||||
{
|
||||
eMBMasterCurErrorType = errorType;
|
||||
}
|
||||
|
||||
#endif /* defined(CONFIG_MB_RTU_MASTER) || defined(CONFIG_MB_ASCII_MASTER) */
|
@ -33,7 +33,15 @@
|
||||
#
|
||||
############################################################################
|
||||
|
||||
CSRCS += portevent.c portother.c portserial.c porttimer.c
|
||||
CSRCS += portother.c
|
||||
|
||||
ifeq ($(CONFIG_MODBUS_SLAVE),y)
|
||||
CSRCS += portevent.c portserial.c porttimer.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_MB_RTU_MASTER),y)
|
||||
CSRCS += portother_m.c portserial_m.c porttimer_m.c portevent_m.c
|
||||
endif
|
||||
|
||||
DEPPATH += --dep-path nuttx
|
||||
VPATH += :nuttx
|
||||
|
@ -86,6 +86,16 @@ void vMBPortTimerPoll(void);
|
||||
bool xMBPortSerialPoll(void);
|
||||
bool xMBPortSerialSetTimeout(uint32_t dwTimeoutMs);
|
||||
|
||||
#if defined(CONFIG_MB_RTU_MASTER) || defined(CONFIG_MB_ASCII_MASTER)
|
||||
void vMBMasterPortEnterCritical(void);
|
||||
void vMBMasterPortExitCritical(void);
|
||||
void vMBMasterPortLog(eMBPortLogLevel eLevel, const char *szModule,
|
||||
const char *szFmt, ...);
|
||||
void vMBMasterPortTimerPoll(void);
|
||||
bool xMBMasterPortSerialPoll(void);
|
||||
bool xMBMasterPortSerialSetTimeout(uint32_t dwTimeoutMs);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
312
modbus/nuttx/portevent_m.c
Normal file
312
modbus/nuttx/portevent_m.c
Normal file
@ -0,0 +1,312 @@
|
||||
/****************************************************************************
|
||||
* apps/modbus/nuttx/portevent_m.c
|
||||
*
|
||||
* FreeModbus Library: NuttX Modbus Master Port
|
||||
* Original work (c) 2006 Christian Walter <wolti@sil.at>
|
||||
* Modified work (c) 2016 Vytautas Lukenskas <lukevyta@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include "modbus/mb.h"
|
||||
#include "modbus/mb_m.h"
|
||||
#include "modbus/mbport.h"
|
||||
#include <sys/time.h>
|
||||
#include <semaphore.h>
|
||||
#include <mqueue.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "port.h"
|
||||
|
||||
#if defined(CONFIG_MB_RTU_MASTER) || defined(CONFIG_MB_ASCII_MASTER)
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define WAITER_EVENTS (EV_MASTER_PROCESS_SUCCESS \
|
||||
| EV_MASTER_ERROR_RESPOND_TIMEOUT \
|
||||
| EV_MASTER_ERROR_RECEIVE_DATA \
|
||||
| EV_MASTER_ERROR_EXECUTE_FUNCTION)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static sem_t bussysem;
|
||||
static sem_t waitersem;
|
||||
static eMBMasterEventType eQueuedEvent;
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
bool xMBMasterPortEventInit(void)
|
||||
{
|
||||
/* Initialize semaphore for waiter */
|
||||
|
||||
sem_init(&waitersem, 0, 0);
|
||||
|
||||
/* No event in queue */
|
||||
|
||||
eQueuedEvent = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool xMBMasterPortEventPost(eMBMasterEventType eEvent)
|
||||
{
|
||||
/* Post waiter sem, if event belongs to one of waiter events */
|
||||
|
||||
if (eEvent & WAITER_EVENTS)
|
||||
{
|
||||
sem_post(&waitersem);
|
||||
}
|
||||
|
||||
eQueuedEvent |= eEvent;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool xMBMasterPortEventGet(eMBMasterEventType * eEvent)
|
||||
{
|
||||
bool xEventHappened = false;
|
||||
|
||||
*eEvent = 0;
|
||||
|
||||
if (eQueuedEvent & ~(WAITER_EVENTS))
|
||||
{
|
||||
|
||||
/* Fetch events by priority */
|
||||
|
||||
if (eQueuedEvent & EV_MASTER_READY)
|
||||
{
|
||||
*eEvent = EV_MASTER_READY;
|
||||
}
|
||||
else if (eQueuedEvent & EV_MASTER_FRAME_RECEIVED)
|
||||
{
|
||||
*eEvent = EV_MASTER_FRAME_RECEIVED;
|
||||
}
|
||||
else if (eQueuedEvent & EV_MASTER_EXECUTE)
|
||||
{
|
||||
*eEvent = EV_MASTER_EXECUTE;
|
||||
}
|
||||
else if (eQueuedEvent & EV_MASTER_FRAME_SENT)
|
||||
{
|
||||
*eEvent = EV_MASTER_FRAME_SENT;
|
||||
}
|
||||
else if (eQueuedEvent & EV_MASTER_FRAME_SENT)
|
||||
{
|
||||
*eEvent = EV_MASTER_FRAME_SENT;
|
||||
}
|
||||
else if (eQueuedEvent & EV_MASTER_ERROR_PROCESS)
|
||||
{
|
||||
*eEvent = EV_MASTER_ERROR_PROCESS;
|
||||
}
|
||||
|
||||
eQueuedEvent &= ~(*eEvent);
|
||||
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)xMBMasterPortSerialPoll();
|
||||
|
||||
/* Check if any of the timers have expired. */
|
||||
|
||||
vMBMasterPortTimerPoll();
|
||||
}
|
||||
|
||||
return xEventHappened;
|
||||
}
|
||||
|
||||
/* This function should init Modbus Master running OS resource */
|
||||
|
||||
void vMBMasterOsResInit(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
if ((res = sem_init(&bussysem, 0, 0)) != OK)
|
||||
{
|
||||
vMBPortLog(MB_LOG_ERROR,
|
||||
"EVENT-INIT",
|
||||
"Can't initialize locking semaphore. Err: %d\n", res);
|
||||
}
|
||||
|
||||
sem_post(&bussysem);
|
||||
}
|
||||
|
||||
/* This function should take Modbus Master running resource.
|
||||
* Note: The resource is defined by Operating System. If you do not use OS,
|
||||
* this function can just return true.
|
||||
*
|
||||
* Input Parmeters:
|
||||
* ulTimeOut the waiting time
|
||||
*
|
||||
* Returned Value:
|
||||
* resource taken result
|
||||
*/
|
||||
|
||||
bool xMBMasterRunResTake(int32_t lTimeOut)
|
||||
{
|
||||
struct timespec time;
|
||||
|
||||
if (lTimeOut == -1)
|
||||
{
|
||||
if (sem_wait(&bussysem) != OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
time.tv_sec = 0;
|
||||
time.tv_nsec = lTimeOut * 1000; /* convert to nano seconds */
|
||||
if (sem_timedwait(&bussysem, &time) != OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* This function should release Modbus Master running resource.
|
||||
* NOTE: The resource is defined by Operating System. If you do not use OS,
|
||||
* this function can just return true.
|
||||
*/
|
||||
|
||||
void vMBMasterRunResRelease(void)
|
||||
{
|
||||
if (sem_post(&bussysem) != OK)
|
||||
{
|
||||
vMBPortLog(MB_LOG_ERROR,
|
||||
"RUN-RES-RELEASE",
|
||||
"Failed to release Modbus Master OS resource\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* This is Modbus Master Respond Timeout error callback function.
|
||||
* NOTE: This function will block modbus master poll.
|
||||
*
|
||||
* Input Parmeters:
|
||||
* ucDestAddress destination slave address
|
||||
* pucPDUData PDU buffer data
|
||||
* ucPDULength PDU buffer length
|
||||
*/
|
||||
|
||||
void vMBMasterErrorCBRespondTimeout(uint8_t ucDestAddress,
|
||||
const uint8_t * pucPDUData,
|
||||
uint16_t usPDULength)
|
||||
{
|
||||
xMBMasterPortEventPost(EV_MASTER_ERROR_RESPOND_TIMEOUT);
|
||||
}
|
||||
|
||||
/* This is Modbus Master receive data error callback function.
|
||||
* NOTE: This function will block modbus master poll.
|
||||
*
|
||||
* Input Parmeters:
|
||||
* ucDestAddress destination slave address
|
||||
* pucPDUData PDU buffer data
|
||||
* usPDULength PDU buffer length
|
||||
*/
|
||||
|
||||
void vMBMasterErrorCBReceiveData(uint8_t ucDestAddress,
|
||||
const uint8_t * pudPDUData,
|
||||
uint16_t usPDULength)
|
||||
{
|
||||
xMBMasterPortEventPost(EV_MASTER_ERROR_RECEIVE_DATA);
|
||||
}
|
||||
|
||||
/* This is Modbus Master execute function error callback function.
|
||||
* NOTE: This function will block modbus master poll.
|
||||
*
|
||||
* Input Parmeters:
|
||||
* ucDestAddress destination slave address
|
||||
* pucPDUData PDU buffer data
|
||||
* usPDULength PDU buffer length
|
||||
*/
|
||||
|
||||
void vMBMasterErrorCBExecuteFunction(uint8_t ucDestAddress,
|
||||
const uint8_t * pucPDUData,
|
||||
uint16_t usPDULength)
|
||||
{
|
||||
xMBMasterPortEventPost(EV_MASTER_ERROR_EXECUTE_FUNCTION);
|
||||
}
|
||||
|
||||
/* This is Modbus Master execute function success callback function.
|
||||
* NOTE: This function will block modbus master poll.
|
||||
*/
|
||||
|
||||
void vMBMasterCBRequestSuccess(void)
|
||||
{
|
||||
xMBMasterPortEventPost(EV_MASTER_PROCESS_SUCCESS);
|
||||
}
|
||||
|
||||
/* This function will wait for Modbus Master request finish and return result.
|
||||
*/
|
||||
|
||||
eMBMasterReqErrCode eMBMasterWaitRequestFinish(void)
|
||||
{
|
||||
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
|
||||
|
||||
/* wait forever for OS event */
|
||||
|
||||
sem_wait(&waitersem);
|
||||
|
||||
if (eQueuedEvent & WAITER_EVENTS)
|
||||
{
|
||||
if (eQueuedEvent & EV_MASTER_PROCESS_SUCCESS)
|
||||
{
|
||||
/* Do nothing */
|
||||
}
|
||||
else if (eQueuedEvent & EV_MASTER_ERROR_RESPOND_TIMEOUT)
|
||||
{
|
||||
eErrStatus = MB_MRE_TIMEDOUT;
|
||||
}
|
||||
else if (eQueuedEvent & EV_MASTER_ERROR_RECEIVE_DATA)
|
||||
{
|
||||
eErrStatus = MB_MRE_REV_DATA;
|
||||
}
|
||||
else if (eQueuedEvent & EV_MASTER_ERROR_EXECUTE_FUNCTION)
|
||||
{
|
||||
eErrStatus = MB_MRE_EXE_FUN;
|
||||
}
|
||||
eQueuedEvent &= ~WAITER_EVENTS;
|
||||
}
|
||||
|
||||
return eErrStatus;
|
||||
}
|
||||
|
||||
#endif /* defined(CONFIG_MB_RTU_MASTER) || defined(CONFIG_MB_ASCII_MASTER) */
|
108
modbus/nuttx/portother_m.c
Normal file
108
modbus/nuttx/portother_m.c
Normal file
@ -0,0 +1,108 @@
|
||||
/****************************************************************************
|
||||
* apps/modbus/nuttx/portother_m.c
|
||||
*
|
||||
* FreeModbus Library: NuttX Port
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#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"
|
||||
|
||||
#include "modbus/mb.h"
|
||||
#include "modbus/mb_m.h"
|
||||
#include "modbus/mbport.h"
|
||||
|
||||
#if defined(CONFIG_MB_RTU_MASTER) || defined(CONFIG_MB_ASCII_MASTER)
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define NELEMS(x) (sizeof((x))/sizeof((x)[0]))
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static FILE *fLogFile = NULL;
|
||||
static eMBPortLogLevel eLevelMax = MB_LOG_DEBUG;
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
void vMBMasterPortLogLevel(eMBPortLogLevel eNewLevelMax)
|
||||
{
|
||||
eLevelMax = eNewLevelMax;
|
||||
}
|
||||
|
||||
void vMBMasterPortLogFile(FILE * fNewLogFile)
|
||||
{
|
||||
fLogFile = fNewLogFile;
|
||||
}
|
||||
|
||||
void vMBMasterPortLog(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* defined(CONFIG_MB_RTU_MASTER) || defined(CONFIG_MB_ASCII_MASTER) */
|
415
modbus/nuttx/portserial_m.c
Normal file
415
modbus/nuttx/portserial_m.c
Normal file
@ -0,0 +1,415 @@
|
||||
/****************************************************************************
|
||||
* apps/modbus/nuttx/portserial_m.c
|
||||
*
|
||||
* FreeModbus Library: NuttX Modbus Master Port
|
||||
* Original work (c) 2006 Christian Walter <wolti@sil.at>
|
||||
* Modified work (c) 2016 Vytautas Lukenskas <lukevyta@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#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 <sys/time.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef CONFIG_SERIAL_TERMIOS
|
||||
# include <termios.h>
|
||||
#endif
|
||||
|
||||
#include "port.h"
|
||||
|
||||
#include "modbus/mb.h"
|
||||
#include "modbus/mb_m.h"
|
||||
#include "modbus/mbport.h"
|
||||
|
||||
#if defined(CONFIG_MB_RTU_MASTER) || defined(CONFIG_MB_ASCII_MASTER)
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#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
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
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
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static bool prvbMBMasterPortSerialRead(uint8_t *pucBuffer, uint16_t usNBytes,
|
||||
uint16_t *usNBytesRead);
|
||||
static bool prvbMBMasterPortSerialWrite(uint8_t *pucBuffer, uint16_t usNBytes);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
static bool prvbMBMasterPortSerialRead(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 = 5000;
|
||||
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;
|
||||
}
|
||||
|
||||
static bool prvbMBMasterPortSerialWrite(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;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
void vMBMasterPortSerialEnable(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 xMBMasterPortSerialInit(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)
|
||||
{
|
||||
vMBMasterPortLog(MB_LOG_ERROR, "SER-INIT",
|
||||
"Can't open serial port %s: %d\n",
|
||||
szDevice, errno);
|
||||
bStatus = false;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_TERMIOS
|
||||
else if (tcgetattr(iSerialFd, &xOldTIO) != 0)
|
||||
{
|
||||
vMBMasterPortLog(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 */)
|
||||
{
|
||||
vMBMasterPortLog(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)
|
||||
{
|
||||
vMBMasterPortLog(MB_LOG_ERROR, "SER-INIT",
|
||||
"Can't set settings for port %s: %d\n",
|
||||
szDevice, errno);
|
||||
}
|
||||
else
|
||||
{
|
||||
vMBMasterPortSerialEnable(false, false);
|
||||
bStatus = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return bStatus;
|
||||
}
|
||||
|
||||
bool xMBMasterPortSerialSetTimeout(uint32_t ulNewTimeoutMs)
|
||||
{
|
||||
if (ulNewTimeoutMs > 0)
|
||||
{
|
||||
ulTimeoutMs = ulNewTimeoutMs;
|
||||
}
|
||||
else
|
||||
{
|
||||
ulTimeoutMs = 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void vMBMasterPortClose( void )
|
||||
{
|
||||
if (iSerialFd != -1)
|
||||
{
|
||||
#ifdef CONFIG_SERIAL_TERMIOS
|
||||
(void)tcsetattr(iSerialFd, TCSANOW, &xOldTIO);
|
||||
#endif
|
||||
(void)close(iSerialFd);
|
||||
iSerialFd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool xMBMasterPortSerialPoll( void )
|
||||
{
|
||||
bool bStatus = true;
|
||||
uint16_t usBytesRead;
|
||||
int i;
|
||||
|
||||
while (bRxEnabled)
|
||||
{
|
||||
if (prvbMBMasterPortSerialRead(&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)pxMBMasterFrameCBByteReceived();
|
||||
}
|
||||
|
||||
uiRxBufferPos = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vMBMasterPortLog(MB_LOG_ERROR, "SER-POLL",
|
||||
"read failed on serial device: %d\n",
|
||||
errno);
|
||||
bStatus = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (bTxEnabled)
|
||||
{
|
||||
while (bTxEnabled)
|
||||
{
|
||||
(void)pxMBMasterFrameCBTransmitterEmpty();
|
||||
|
||||
/* Call the modbus stack to let him fill the buffer. */
|
||||
}
|
||||
|
||||
if (!prvbMBMasterPortSerialWrite(&ucBuffer[0], uiTxBufferPos))
|
||||
{
|
||||
vMBMasterPortLog(MB_LOG_ERROR, "SER-POLL",
|
||||
"write failed on serial device: %d\n",
|
||||
errno);
|
||||
bStatus = false;
|
||||
}
|
||||
}
|
||||
|
||||
return bStatus;
|
||||
}
|
||||
|
||||
bool xMBMasterPortSerialPutByte(int8_t ucByte)
|
||||
{
|
||||
ASSERT(uiTxBufferPos < BUF_SIZE);
|
||||
ucBuffer[uiTxBufferPos] = ucByte;
|
||||
uiTxBufferPos++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool xMBMasterPortSerialGetByte(int8_t *pucByte)
|
||||
{
|
||||
ASSERT(uiRxBufferPos < BUF_SIZE);
|
||||
*pucByte = ucBuffer[uiRxBufferPos];
|
||||
uiRxBufferPos++;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* defined(CONFIG_MB_RTU_MASTER) || defined(CONFIG_MB_ASCII_MASTER) */
|
176
modbus/nuttx/porttimer_m.c
Normal file
176
modbus/nuttx/porttimer_m.c
Normal file
@ -0,0 +1,176 @@
|
||||
/****************************************************************************
|
||||
* apps/modbus/nuttx/porttimer_m.c
|
||||
*
|
||||
* FreeModbus Library: NuttX Modbus Master Port
|
||||
* Original work (c) 2006 Christian Walter <wolti@sil.at>
|
||||
* Modified work (c) 2016 Vytautas Lukenskas <lukevyta@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "port.h"
|
||||
|
||||
#include "modbus/mb.h"
|
||||
#include "modbus/mb_m.h"
|
||||
#include "modbus/mbport.h"
|
||||
|
||||
#if defined(CONFIG_MB_RTU_MASTER) || defined(CONFIG_MB_ASCII_MASTER)
|
||||
|
||||
#ifndef CONFIG_MB_MASTER_DELAY_MS_CONVERT
|
||||
# define MB_MASTER_DELAY_MS_CONVERT 200
|
||||
#else
|
||||
# define MB_MASTER_DELAY_MS_CONVERT CONFIG_MB_MASTER_DELAY_MS_CONVERT
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_MB_MASTER_TIMEOUT_MS_RESPOND
|
||||
# define MB_MASTER_TIMEOUT_MS_RESPOND 1000
|
||||
#else
|
||||
# define MB_MASTER_TIMEOUT_MS_RESPOND CONFIG_MB_MASTER_TIMEOUT_MS_RESPOND
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
uint32_t ulTimeOut; /* current timeout duration */
|
||||
uint32_t ulTimeoutT35; /* 3.5 byte transmission duration */
|
||||
uint32_t ulTimeoutConvertDelay; /* timeout after broadcast message */
|
||||
uint32_t ulTimeoutResponse; /* response timeout duration */
|
||||
static struct timeval xTimeLast;
|
||||
bool bTimeoutEnable; /* timeout is active */
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
void vMBMasterPortTimersEnable( void )
|
||||
{
|
||||
int res = gettimeofday(&xTimeLast, NULL);
|
||||
|
||||
ASSERT(res == 0);
|
||||
bTimeoutEnable = true;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
bool xMBMasterPortTimersInit(uint16_t usTimeOut50us)
|
||||
{
|
||||
/* Configure all timeout values */
|
||||
|
||||
ulTimeoutT35 = usTimeOut50us / 20U;
|
||||
if (ulTimeoutT35 == 0)
|
||||
{
|
||||
ulTimeoutT35 = 1;
|
||||
}
|
||||
|
||||
ulTimeoutConvertDelay = MB_MASTER_DELAY_MS_CONVERT;
|
||||
if (ulTimeoutConvertDelay == 0)
|
||||
{
|
||||
ulTimeoutConvertDelay = 1;
|
||||
}
|
||||
|
||||
ulTimeoutResponse = MB_MASTER_TIMEOUT_MS_RESPOND;
|
||||
if (ulTimeoutResponse == 0)
|
||||
{
|
||||
ulTimeoutResponse = 1;
|
||||
}
|
||||
|
||||
ulTimeOut = ulTimeoutT35;
|
||||
|
||||
return xMBMasterPortSerialSetTimeout(ulTimeOut);
|
||||
}
|
||||
|
||||
void xMBMasterPortTimersClose()
|
||||
{
|
||||
/* Does not use any hardware resources. */
|
||||
}
|
||||
|
||||
INLINE void vMBMasterPortTimersT35Enable( void )
|
||||
{
|
||||
vMBMasterPortTimersEnable();
|
||||
ulTimeOut = ulTimeoutT35;
|
||||
vMBMasterSetCurTimerMode(MB_TMODE_T35);
|
||||
}
|
||||
|
||||
INLINE void vMBMasterPortTimersConvertDelayEnable( void )
|
||||
{
|
||||
vMBMasterPortTimersEnable();
|
||||
ulTimeOut = ulTimeoutConvertDelay;
|
||||
vMBMasterSetCurTimerMode(MB_TMODE_CONVERT_DELAY);
|
||||
}
|
||||
|
||||
INLINE void vMBMasterPortTimersRespondTimeoutEnable( void )
|
||||
{
|
||||
vMBMasterPortTimersEnable();
|
||||
ulTimeOut = ulTimeoutResponse;
|
||||
vMBMasterSetCurTimerMode( MB_TMODE_RESPOND_TIMEOUT );
|
||||
}
|
||||
|
||||
void vMBMasterPortTimerPoll( void )
|
||||
{
|
||||
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)pxMBMasterPortCBTimerExpired();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void vMBMasterPortTimersDisable()
|
||||
{
|
||||
bTimeoutEnable = false;
|
||||
}
|
||||
|
||||
#endif /* if defined(CONFIG_MB_RTU_MASTER) || defined(CONFIG_MB_ASCII_MASTER) */
|
@ -33,9 +33,22 @@
|
||||
#
|
||||
############################################################################
|
||||
|
||||
ifeq ($(CONFIG_MB_RTU_ENABLED),y)
|
||||
compile_rtu=
|
||||
|
||||
ifeq ($(CONFIG_MB_RTU_ENABLED),y)
|
||||
compile_rtu=yes
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_MB_RTU_MASTER),y)
|
||||
compile_rtu=yes
|
||||
endif
|
||||
|
||||
ifdef compile_rtu
|
||||
CSRCS += mbcrc.c
|
||||
ifeq ($(CONFIG_MB_RTU_ENABLED),y)
|
||||
CSRCS += mbrtu.c
|
||||
endif
|
||||
|
||||
CSRCS += mbcrc.c mbrtu.c
|
||||
ifeq ($(CONFIG_MB_RTU_MASTER),y)
|
||||
CSRCS += mbrtu_m.c
|
||||
endif
|
||||
|
@ -40,7 +40,7 @@
|
||||
|
||||
#include "port.h"
|
||||
|
||||
#include "modbus/mb.h">
|
||||
#include "modbus/mb.h"
|
||||
#include "modbus/mbframe.h"
|
||||
#include "modbus/mbport.h"
|
||||
|
||||
|
@ -54,20 +54,6 @@ bool xMBRTUTransmitFSM(void);
|
||||
bool xMBRTUTimerT15Expired(void);
|
||||
bool xMBRTUTimerT35Expired(void);
|
||||
|
||||
#if defined(CONFIG_RTU_ASCII_MASTER)
|
||||
eMBErrorCode eMBMasterRTUInit(uint8_t ucPort, speed_t ulBaudRate,
|
||||
eMBParity eParity);
|
||||
void eMBMasterRTUStart(void);
|
||||
void eMBMasterRTUStop(void);
|
||||
eMBErrorCode eMBMasterRTUReceive(uint8_t *pucRcvAddress, uint8_t **pucFrame,
|
||||
uint16_t *pusLength);
|
||||
eMBErrorCode eMBMasterRTUSend(uint8_t slaveAddress, const uint8_t *pucFrame,
|
||||
uint16_t usLength);
|
||||
bool xMBMasterRTUReceiveFSM(void);
|
||||
bool xMBMasterRTUTransmitFSM(void);
|
||||
bool xMBMasterRTUTimerExpired(void);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -36,19 +36,20 @@
|
||||
#include <nuttx/config.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "port.h"
|
||||
|
||||
#include "modbus/mb.h"
|
||||
#include "modbus/mb_m.h"
|
||||
#include "mbrtu.h"
|
||||
#include "mbrtu_m.h"
|
||||
#include "modbus/mbframe.h"
|
||||
|
||||
#include "mbcrc.h"
|
||||
|
||||
#include "modbus/mbport.h"
|
||||
|
||||
#if defined(CONFIG_RTU_ASCII_MASTER)
|
||||
#if defined(CONFIG_MB_RTU_MASTER)
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
@ -182,7 +183,7 @@ eMBErrorCode eMBMasterRTUReceive(uint8_t *pucRcvAddress, uint8_t **pucFrame,
|
||||
eMBErrorCode eStatus = MB_ENOERR;
|
||||
|
||||
ENTER_CRITICAL_SECTION();
|
||||
assert_param(usMasterRcvBufferPos < MB_SER_PDU_SIZE_MAX);
|
||||
ASSERT(usMasterRcvBufferPos < MB_SER_PDU_SIZE_MAX);
|
||||
|
||||
/* Length and CRC check */
|
||||
|
||||
@ -272,12 +273,12 @@ bool xMBMasterRTUReceiveFSM(void)
|
||||
bool xTaskNeedSwitch = false;
|
||||
uint8_t ucByte;
|
||||
|
||||
assert_param((eSndState == STATE_M_TX_IDLE) ||
|
||||
(eSndState == STATE_M_TX_XFWR));
|
||||
ASSERT((eSndState == STATE_M_TX_IDLE) ||
|
||||
(eSndState == STATE_M_TX_XFWR));
|
||||
|
||||
/* Always read the character. */
|
||||
|
||||
(void)xMBMasterPortSerialGetByte((CHAR *) & ucByte);
|
||||
(void)xMBMasterPortSerialGetByte((uint8_t *) & ucByte);
|
||||
|
||||
switch (eRcvState)
|
||||
{
|
||||
@ -346,7 +347,7 @@ bool xMBMasterRTUTransmitFSM(void)
|
||||
{
|
||||
bool xNeedPoll = false;
|
||||
|
||||
assert_param(eRcvState == STATE_M_RX_IDLE);
|
||||
ASSERT(eRcvState == STATE_M_RX_IDLE);
|
||||
|
||||
switch (eSndState)
|
||||
{
|
||||
@ -365,7 +366,7 @@ bool xMBMasterRTUTransmitFSM(void)
|
||||
|
||||
if (usMasterSndBufferCount != 0)
|
||||
{
|
||||
xMBMasterPortSerialPutByte((CHAR) * pucMasterSndBufferCur);
|
||||
xMBMasterPortSerialPutByte((uint8_t) * pucMasterSndBufferCur);
|
||||
pucMasterSndBufferCur++; /* next byte in sendbuffer. */
|
||||
usMasterSndBufferCount--;
|
||||
}
|
||||
@ -431,10 +432,10 @@ bool xMBMasterRTUTimerExpired(void)
|
||||
/* Function called in an illegal state. */
|
||||
|
||||
default:
|
||||
assert_param((eRcvState == STATE_M_RX_INIT) ||
|
||||
(eRcvState == STATE_M_RX_RCV) ||
|
||||
(eRcvState == STATE_M_RX_ERROR) ||
|
||||
(eRcvState == STATE_M_RX_IDLE));
|
||||
ASSERT((eRcvState == STATE_M_RX_INIT) ||
|
||||
(eRcvState == STATE_M_RX_RCV) ||
|
||||
(eRcvState == STATE_M_RX_ERROR) ||
|
||||
(eRcvState == STATE_M_RX_IDLE));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -458,8 +459,8 @@ bool xMBMasterRTUTimerExpired(void)
|
||||
/* Function called in an illegal state. */
|
||||
|
||||
default:
|
||||
assert_param((eSndState == STATE_M_TX_XFWR) ||
|
||||
(eSndState == STATE_M_TX_IDLE));
|
||||
ASSERT((eSndState == STATE_M_TX_XFWR) ||
|
||||
(eSndState == STATE_M_TX_IDLE));
|
||||
break;
|
||||
}
|
||||
|
||||
|
60
modbus/rtu/mbrtu_m.h
Normal file
60
modbus/rtu/mbrtu_m.h
Normal file
@ -0,0 +1,60 @@
|
||||
/****************************************************************************
|
||||
* apps/modbus/rtu/mbrtu_m.h
|
||||
*
|
||||
* FreeModbus Library: A portable Modbus implementation for Modbus ASCII/RTU.
|
||||
* Copyright (c) 2013 China Beijing Armink <armink.ztl@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __APPS_MODBUS_RTU_MBRTU_M_H
|
||||
#define __APPS_MODBUS_RTU_MBRTU_M_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
eMBErrorCode eMBMasterRTUInit(uint8_t ucPort, speed_t ulBaudRate,
|
||||
eMBParity eParity);
|
||||
void eMBMasterRTUStart(void);
|
||||
void eMBMasterRTUStop(void);
|
||||
eMBErrorCode eMBMasterRTUReceive(uint8_t *pucRcvAddress, uint8_t **pucFrame,
|
||||
uint16_t *pusLength);
|
||||
eMBErrorCode eMBMasterRTUSend(uint8_t slaveAddress, const uint8_t *pucFrame,
|
||||
uint16_t usLength);
|
||||
bool xMBMasterRTUReceiveFSM(void);
|
||||
bool xMBMasterRTUTransmitFSM(void);
|
||||
bool xMBMasterRTUTimerExpired(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __APPS_MODBUS_RTU_MBRTU_M_H */
|
Loading…
x
Reference in New Issue
Block a user