feat support freemobus lib in connection framework from Liu_Weichao

it is OK
This commit is contained in:
IACU 2023-11-29 14:40:48 +08:00
commit c55286286e
103 changed files with 7825 additions and 787 deletions

View File

@ -281,6 +281,7 @@ menu "test app"
menuconfig USER_TEST_MQTTCLIENT
bool "Config test mqtt client"
default n
select LIB_USING_CJSON
menuconfig USER_TEST_FTPCLIENT
bool "Config test ftp client"

View File

@ -150,7 +150,9 @@ ifeq ($(CONFIG_ADD_XIZI_FEATURES),y)
endif
ifeq ($(CONFIG_USER_TEST_FTPCLIENT_RISCV),y)
SRC_FILES += test_ftpclient_riscv/test_ftpclient_riscv.c
ifeq ($(CONFIG_BSP_USING_W5500),y)
SRC_FILES += test_ftpclient_riscv/test_ftpclient_riscv.c
endif
endif
ifeq ($(CONFIG_USER_TEST_LORA_P2P),y)

View File

@ -22,6 +22,7 @@
#include <transform.h>
#ifdef ADD_XIZI_FEATURES
#ifdef BSP_USING_W5500
#include <socket.h>
#define BUFF_SIZE 128
@ -189,6 +190,6 @@ PRIV_SHELL_CMD_FUNCTION(TestSocketAsClient, a w5500 client-ip-port-msg test samp
#endif
#endif
#endif

View File

@ -98,6 +98,7 @@ void TestLora(int argc, char *argv[])
uart_cfg.serial_buffer_size = SERIAL_RB_BUFSZ;
uart_cfg.serial_timeout = 1000;
uart_cfg.is_ext_uart = 0;
uart_cfg.dev_recv_callback = NULL;
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
ioctl_cfg.args = (void *)&uart_cfg;

View File

@ -62,6 +62,7 @@ static struct SerialDataCfg serial_cfg =
.serial_buffer_size = SERIAL_RB_BUFSZ,
.serial_timeout = E220_DAFAULT_SERIAL_TIMEOUT, // 串口超时配置
.is_ext_uart = 0,
.dev_recv_callback = NULL,
};
enum LoraMode current_mode = -1; // 当前模块处于什么模式

View File

@ -138,6 +138,7 @@ void Test485(void)
uart_cfg.serial_buffer_size = SERIAL_RB_BUFSZ;
uart_cfg.serial_timeout = -1;
uart_cfg.is_ext_uart = 0;
uart_cfg.dev_recv_callback = NULL;
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
ioctl_cfg.args = (void *)&uart_cfg;

View File

@ -70,6 +70,7 @@ void Test485(void)
uart_cfg.serial_buffer_size = SERIAL_RB_BUFSZ;
uart_cfg.serial_timeout = 1000;
uart_cfg.is_ext_uart = 0;
uart_cfg.dev_recv_callback = NULL;
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
ioctl_cfg.args = (void *)&uart_cfg;

View File

@ -68,6 +68,7 @@ void TestUart(int argc, char* argv[])
uart_cfg.serial_buffer_size = SERIAL_RB_BUFSZ;
uart_cfg.serial_timeout = -1;
uart_cfg.is_ext_uart = 0;
uart_cfg.dev_recv_callback = NULL;
struct PrivIoctlCfg ioctl_cfg;
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;

View File

@ -175,6 +175,7 @@ static int Ec200tIoctl(struct Adapter *adapter, int cmd, void *args)
serial_cfg.ext_uart_no = ADAPTER_EC200T_DRIVER_EXT_PORT;
serial_cfg.port_configure = PORT_CFG_INIT;
#endif
serial_cfg.dev_recv_callback = NULL;
struct PrivIoctlCfg ioctl_cfg;
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;

View File

@ -268,6 +268,7 @@ static int Hc08Open(struct Adapter *adapter)
serial_cfg.ext_uart_no = ADAPTER_HC08_DRIVER_EXT_PORT;
serial_cfg.port_configure = PORT_CFG_INIT;
#endif
serial_cfg.dev_recv_callback = NULL;
struct PrivIoctlCfg ioctl_cfg;
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
@ -326,6 +327,7 @@ static int Hc08Ioctl(struct Adapter *adapter, int cmd, void *args)
serial_cfg.ext_uart_no = ADAPTER_HC08_DRIVER_EXT_PORT;
serial_cfg.port_configure = PORT_CFG_INIT;
#endif
serial_cfg.dev_recv_callback = NULL;
serial_cfg.serial_timeout = -1;

View File

@ -407,6 +407,7 @@ static int Hfa21EthernetIoctl(struct Adapter *adapter, int cmd, void *args)
serial_cfg.ext_uart_no = ADAPTER_HFA21_DRIVER_EXT_PORT;
serial_cfg.port_configure = PORT_CFG_INIT;
#endif
serial_cfg.dev_recv_callback = NULL;
struct PrivIoctlCfg ioctl_cfg;
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;

View File

@ -0,0 +1,10 @@
config CONNECTION_MODBUS
bool "Using industrial fieldbus ModBus"
default n
if CONNECTION_MODBUS
source "$APP_DIR/Framework/connection/industrial_fieldbus/modbus/Kconfig"
endif

View File

@ -1,3 +1,7 @@
SRC_DIR :=
ifeq ($(CONFIG_CONNECTION_MODBUS),y)
SRC_DIR += modbus
endif
include $(KERNEL_ROOT)/compiler.mk

View File

@ -1,101 +0,0 @@
/*
* FreeModbus Libary: BARE Demo Application
* Copyright (C) 2006 Christian Walter <wolti@sil.at>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id$
*/
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
/* ----------------------- Defines ------------------------------------------*/
#define REG_INPUT_START 1000
#define REG_INPUT_NREGS 4
/* ----------------------- Static variables ---------------------------------*/
static USHORT usRegInputStart = REG_INPUT_START;
static USHORT usRegInputBuf[REG_INPUT_NREGS];
/* ----------------------- Start implementation -----------------------------*/
int
main( void )
{
eMBErrorCode eStatus;
eStatus = eMBInit( MB_RTU, 0x0A, 0, 38400, MB_PAR_EVEN );
/* Enable the Modbus Protocol Stack. */
eStatus = eMBEnable( );
for( ;; )
{
( void )eMBPoll( );
/* Here we simply count the number of poll cycles. */
usRegInputBuf[0]++;
}
}
eMBErrorCode
eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
{
eMBErrorCode eStatus = MB_ENOERR;
int iRegIndex;
if( ( usAddress >= REG_INPUT_START )
&& ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
{
iRegIndex = ( int )( usAddress - usRegInputStart );
while( usNRegs > 0 )
{
*pucRegBuffer++ =
( unsigned char )( usRegInputBuf[iRegIndex] >> 8 );
*pucRegBuffer++ =
( unsigned char )( usRegInputBuf[iRegIndex] & 0xFF );
iRegIndex++;
usNRegs--;
}
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}
eMBErrorCode
eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs,
eMBRegisterMode eMode )
{
return MB_ENOREG;
}
eMBErrorCode
eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils,
eMBRegisterMode eMode )
{
return MB_ENOREG;
}
eMBErrorCode
eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
return MB_ENOREG;
}

View File

@ -1,54 +0,0 @@
/*
* FreeModbus Libary: BARE Port
* 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$
*/
#ifndef _PORT_H
#define _PORT_H
#include <assert.h>
#include <inttypes.h>
#define INLINE inline
#define PR_BEGIN_EXTERN_C extern "C" {
#define PR_END_EXTERN_C }
#define ENTER_CRITICAL_SECTION( )
#define EXIT_CRITICAL_SECTION( )
typedef uint8_t BOOL;
typedef unsigned char UCHAR;
typedef char CHAR;
typedef uint16_t USHORT;
typedef int16_t SHORT;
typedef uint32_t ULONG;
typedef int32_t LONG;
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#endif

View File

@ -1,58 +0,0 @@
/*
* FreeModbus Libary: BARE Port
* 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$
*/
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.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;
}
return xEventHappened;
}

View File

@ -1,152 +0,0 @@
/*
* FreeModbus Libary: BARE Port
* 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$
*/
#include <adapter.h>
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
/* ----------------------- static functions ---------------------------------*/
static void prvvUARTTxReadyISR( void );
static void prvvUARTRxISR( void );
/* ----------------------- Start implementation -----------------------------*/
void
vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
{
/* If xRXEnable enable serial receive interrupts. If xTxENable enable
* transmitter empty interrupts.
*/
if(xRxEnable && !xTxEnable)//接收数据
{
Set485Input();
}
if(!xRxEnable && xTxEnable)
{
Set485Output();
}
}
BOOL
xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
{
struct SerialDataCfg serial_cfg;
memset(&serial_cfg, 0 ,sizeof(struct SerialDataCfg));
serial_cfg.serial_baud_rate = (uint32_t)ulBaudRate;
serial_cfg.serial_data_bits = (uint8_t)ucDataBits;
serial_cfg.serial_stop_bits = STOP_BITS_1;
serial_cfg.serial_buffer_size = SERIAL_RB_BUFSZ;
serial_cfg.serial_parity_mode = (uint8_t)eParity;
serial_cfg.serial_bit_order = STOP_BITS_1;
serial_cfg.serial_invert_mode = NRZ_NORMAL;
serial_cfg.is_ext_uart = 0;
return FALSE;
}
BOOL
xMBPortSerialPutByte( CHAR ucByte )
{
/* Put a byte in the UARTs transmit buffer. This function is called
* by the protocol stack if pxMBFrameCBTransmitterEmpty( ) has been
* called. */
Set485Output();
PrivTaskDelay(20);
PrivWrite(uart_fd, ucByte, 1);
PrivTaskDelay(15);
Set485Input();
return TRUE;
}
BOOL
xMBPortSerialGetByte( CHAR * pucByte )
{
/* Return the byte in the UARTs receive buffer. This function is called
* by the protocol stack after pxMBFrameCBByteReceived( ) has been called.
*/
PrivRead(uart_fd, pucByte, 1);//
//need to wait 30ms , make sure write cmd again and receive data successfully
PrivTaskDelay(30);
return TRUE;
}
/* Create an interrupt handler for the transmit buffer empty interrupt
* (or an equivalent) for your target processor. This function should then
* call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that
* a new character can be sent. The protocol stack will then call
* xMBPortSerialPutByte( ) to send the character.
*/
static void prvvUARTTxReadyISR( void )
{
pxMBFrameCBTransmitterEmpty( );
}
/* Create an interrupt handler for the receive interrupt for your target
* processor. This function should then call pxMBFrameCBByteReceived( ). The
* protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
* character.
*/
static void prvvUARTRxISR( void )
{
pxMBFrameCBByteReceived( );
}
static int pin_fd = 0;
static int uart_fd = 0;
/**
* @description: Set Uart 485 Input
* @return
*/
static void Set485Input(void)
{
struct PinStat pin_stat;
pin_stat.pin = 2;//CONTROL_FRAMEWORK_UART_485_DIR
pin_stat.val = GPIO_LOW;
PrivWrite(pin_fd, &pin_stat, 1);
}
/**
* @description: Set Uart 485 Output
* @return
*/
static void Set485Output(void)
{
struct PinStat pin_stat;
pin_stat.pin = 2;//CONTROL_FRAMEWORK_UART_485_DIR
pin_stat.val = GPIO_HIGH;
PrivWrite(pin_fd, &pin_stat, 1);
}

View File

@ -1,62 +0,0 @@
/*
* FreeModbus Libary: BARE Port
* 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$
*/
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
/* ----------------------- static functions ---------------------------------*/
static void prvvTIMERExpiredISR( void );
/* ----------------------- Start implementation -----------------------------*/
BOOL
xMBPortTimersInit( USHORT usTim1Timerout50us )
{
PrivTaskDelay(usTim1Timerout50us);
return FALSE;
}
inline void
vMBPortTimersEnable( )
{
/* Enable the timer with the timeout passed to xMBPortTimersInit( ) */
PrivTaskDelay(usTim1Timerout50us);
}
inline void
vMBPortTimersDisable( )
{
/* Disable any pending timers. */
}
/* Create an ISR which is called whenever the timer has expired. This function
* must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that
* the timer has expired.
*/
static void prvvTIMERExpiredISR( void )
{
( void )pxMBPortCBTimerExpired( );
}

View File

@ -0,0 +1,214 @@
choice
prompt "choose ModBus type"
default CONNECTION_MODBUS_USING_RTU
config CONNECTION_MODBUS_USING_RTU
bool "select ModBus_RTU function"
config CONNECTION_MODBUS_USING_TCP
bool "select ModBus_TCP function"
endchoice
if CONNECTION_MODBUS_USING_RTU
choice
prompt "choose ModBus_RTU work mode"
default CONNECTION_MODBUS_USING_RTU_MASTER
config CONNECTION_MODBUS_USING_RTU_MASTER
bool "select ModBus_RTU master mode"
config CONNECTION_MODBUS_USING_RTU_SLAVE
bool "select ModBus_RTU slave mode"
endchoice
if CONNECTION_MODBUS_USING_RTU_MASTER
menu "ModBus_RTU Master Register Configure"
config X_M_DISCRETE_INPUT_START
int "master discrete input start address"
default 0
config X_M_DISCRETE_INPUT_NDISCRETES
int "master discrete input discretes numbers"
default 16
config X_M_COIL_START
int "master coil start address"
default 0
config X_M_COIL_NCOILS
int "master coil numbers"
default 64
config X_M_REG_INPUT_START
int "master input start address"
default 0
config X_M_REG_INPUT_NREGS
int "master input regs numbers"
default 100
config X_M_REG_HOLDING_START
int "master holding start address"
default 0
config X_M_REG_HOLDING_NREGS
int "master holding regs numbers"
default 100
config X_M_HD_RESERVE
int "master holding reserve numbers"
default 0
config X_M_IN_RESERVE
int "master input reserve numbers"
default 0
config X_M_CO_RESERVE
int "master coil reserve numbers"
default 0
config X_M_DI_RESERVE
int "master discrete reserve numbers"
default 0
endmenu
endif
if CONNECTION_MODBUS_USING_RTU_SLAVE
menu "ModBus_RTU Slave Register Configure"
config X_S_DISCRETE_INPUT_START
int "slave discrete input start address"
default 0
config X_S_DISCRETE_INPUT_NDISCRETES
int "slave discrete input discretes numbers"
default 16
config X_S_COIL_START
int "slave coil start address"
default 0
config X_S_COIL_NCOILS
int "slave coil numbers"
default 64
config X_S_REG_INPUT_START
int "slave input start address"
default 0
config X_S_REG_INPUT_NREGS
int "slave input regs numbers"
default 100
config X_S_REG_HOLDING_START
int "slave holding start address"
default 0
config X_S_REG_HOLDING_NREGS
int "slave holding regs numbers"
default 100
config X_S_HD_RESERVE
int "slave holding reserve numbers"
default 0
config X_S_IN_RESERVE
int "slave input reserve numbers"
default 0
config X_S_CO_RESERVE
int "slave coil reserve numbers"
default 0
config X_S_DI_RESERVE
int "slave discrete reserve numbers"
default 0
endmenu
endif
config CONNECTION_MODBUS_RTU_UART_485_DIR
int "serial 485 direction pin number"
default "67"
config CONNECTION_MODBUS_RTU_PIN_DEV
string "device pin dev path for serial 485 DIR"
default "/dev/pin_dev"
config CONNECTION_MODBUS_RTU_EXTUART
bool "Using extra uart to support serial 485"
default n
config CONNECTION_MODBUS_RTU_UART_DEV
string "device uart dev path for serial 485"
default "/dev/usart4_dev4"
depends on !CONTROL_FRAMEWORK_DRIVER_EXTUART
if CONTROL_FRAMEWORK_DRIVER_EXTUART
config CONNECTION_MODBUS_RTU_UART_DEV
string "device extra uart dev path for serial 485"
default "/dev/extuart_dev0"
config CONNECTION_MODBUS_RTU_UART_DEV_EXT_PORT
int "if device using extuart, choose port"
default "0"
endif
endif
if CONNECTION_MODBUS_USING_TCP
config CONNECTION_MODBUS_USING_TCP_SLAVE
bool "select ModBus_TCP slave mode"
default y
if CONNECTION_MODBUS_USING_TCP_SLAVE
menu "ModBus_TCP Slave Register Configure"
config X_S_DISCRETE_INPUT_START
int "slave discrete input start address"
default 0
config X_S_DISCRETE_INPUT_NDISCRETES
int "slave discrete input discretes numbers"
default 16
config X_S_COIL_START
int "slave coil start address"
default 0
config X_S_COIL_NCOILS
int "slave coil numbers"
default 64
config X_S_REG_INPUT_START
int "slave input start address"
default 0
config X_S_REG_INPUT_NREGS
int "slave input regs numbers"
default 100
config X_S_REG_HOLDING_START
int "slave holding start address"
default 0
config X_S_REG_HOLDING_NREGS
int "slave holding regs numbers"
default 100
config X_S_HD_RESERVE
int "slave holding reserve numbers"
default 0
config X_S_IN_RESERVE
int "slave input reserve numbers"
default 0
config X_S_CO_RESERVE
int "slave coil reserve numbers"
default 0
config X_S_DI_RESERVE
int "slave discrete reserve numbers"
default 0
endmenu
endif
endif

View File

@ -1,3 +1,11 @@
SRC_DIR :=
SRC_DIR := freemodbus-latest
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_RTU),y)
SRC_FILES :=
endif
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_TCP),y)
SRC_FILES :=
endif
include $(KERNEL_ROOT)/compiler.mk

View File

@ -1,65 +0,0 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file adapter_Modbus_rtu.c
* @brief Implement the connection 4G adapter function
* @version 1.1
* @author AIIT XIUOS Lab
* @date 2021.06.25
*/
#include <adapter.h>
static int AdapterModbusRtuRegister(struct Adapter *adapter)
{
int ret = 0;
strncpy(adapter->name, ADAPTER_MODBUS_RTU_NAME, NAME_NUM_MAX);
adapter->net_protocol = PROTOCOL_NONE;//IP层协议类型串口没有此层
adapter->net_role = SLAVE;
adapter->adapter_status = UNREGISTERED;
ret = AdapterDeviceRegister(adapter);
if (ret < 0) {
printf("AdapterModbusRtu register error\n");
return -1;
}
return ret;
}
int AdapterModbusRtuInit(void)
{
int ret = 0;
struct Adapter *adapter = PrivMalloc(sizeof(struct Adapter));
if (!adapter) {
PrivFree(adapter);
return -1;
}
memset(adapter, 0, sizeof(struct Adapter));
ret = AdapterModbusRtuRegister(adapter);
if (ret < 0) {
printf("AdapterModbusRtuInit register ModbusRtu adapter error\n");
PrivFree(adapter);
return -1;
}
return ret;
}

View File

@ -0,0 +1,329 @@
2013-10-17 (REL_1_6_0) Armink <armink.ztl@gmail.com>
Notes: Added modbus master.
2010-05-06 (REL_1_5_0) Christian Walter <cwalter@embedded-solutions.at>
Notes: Added support for Atmel AT91SAM3S (Cortex M3) for IAR.
Detailed notes:
- FEATURES (ATSAM3S) : Added new port.
2007-08-28 (REL_1_4_0) Christian Walter <wolti@sil.at>:
Notes: Added support for HCS08. Fixed some small bugs in the documentation
for the porting layer.
Detailed notes:
- FEATURES (HCS08) : Added new port.
- BUGS (ALL) : Fixed some small bugs in the porting guide.
2007-07-17 (REL_1_3_0) Christian Walter <wolti@sil.at>:
Notes: Added ARM7/AT91SAM7X port. Added Linux/TCP port from Steven Guo.
Detailed notes:
- FEATURES (ARM7): Added ARM7/AT91SAM7x port.
- FEATURES (LINUX): Added Linux/TCP port from Steven Guo.
- BUGS (ALL): Fixed bug in <eMBFuncReadInputRegister> where the high
byte of the register count was ignored. This does not have a
practical impact because the actual number of registers is always
lower.
2007-07-17 (REL_1_3_0) Christian Walter <wolti@sil.at>:
Notes: Added Linux/TCP port. Fixed bug in MSP430 port.
Detailted notes:
- FEATURE (LINUX): Added Linux/TCP port.
- BUGS (MSP430): Fixed bug with calculating the timer value.
2007-04-25 (REL_1_2_0) Christian Walter <wolti@sil.at>:
Notes: Added LPC214X ARM port with Keil compiler. Added Z8Encore port for
Z8F6422 microcontroller.
Detailed notes:
- FEATURE (ARM): Added LPC214X ARM port for Keil ARM 2.41.
- FEATURE (Z8ENCORE): Added Z8F6422 for Z8Encore using the ZDS II - Z8
Encore! development tools.
2007-02-18 (REL_1_1_2) Christian Walter <wolti@sil.at>:
Notes: Fixed typo with the defined defining the supported Modbus
functions. Fixed bug when illegal slave address was passed to eMBInit
where the error was not detected. Fixed typo in the holding registers
where the frame for write multiple registers was parsed with the wrong
constants. The fix is not critical because the values matched. Fixed bug
in discrete input registers implementation where the frame was not parsed
correctly. Added new support for a CodeWarrior Coldfire port.
Detailed notes:
- BUG (ALL): Modbus functions are compiled into the stack conditionally
by changing the MB_FUNC_XXX defines to either true(1) or false(0).
The defines for MB_FUNC_READ_HOLDING and MB_FUNC_WRITE_HOLDING
were wrong.
- BUG (ALL): eMBInit did not correctly check for addresses. Therefore
is was possible to start the Modbus stack with an address of 0
or one > 247.
- BUG (ALL): eMBFuncWriteHoldingRegister should use
MB_PDU_FUNC_WRITE_MUL_ADDR_OFF and not MB_PDU_FUNC_READ_ADDR_OFF.
- BUG (ALL): eMBFuncReadDiscreteInputs calculated the number of discrete
registers to read wrong.
- FEATURE (ALL): Fixed some warnings in the code.
2006-11-19 (REL_1_1_1) Christian Walter <wolti@sil.at>:
Notes: Fixed bug in Read/Write Multiple Registers function where
the registers addresses where calculated wrong.
Fixed bug in RTU and ASCII with the resource allocation in case of
an error.
Changed license to BSD style licsense.
Detailed notes:
- OTHER (ALL): License is now BSD for protocol stack.
- BUG (ALL): The registers address received in a Modbus frame
must be converted to application addresses. The code for this
conversion was missing and therefore has lead to error when
this function was used (Registers of by one, Start at > 1).
- BUG (ALL): If the serial initialization within the porting fails
a timer is still allocated in eMBRTUInit and eMBASCIIInit. This
can lead to a memory leak depending upon the implementation of the
porting layer.
- FEATURE (MCF5235): Added sample shell scripts for testing.
- FEATURE (MSP430): Added sample shell script for testing and
changed default values to match the other ports.
2006-10-30 (REL_1_1_0) Christian Walter <wolti@sil.at>:
Notes: Added support for Read/Write Multiple Registers function
(0x17). Added some tips to reduce memory requirements.
Added MSP430 Port for GCC and Rowley Crossworks.
Detailed notes:
- FEATURE (MSP430): Added new MSP430 port.
- FEATURE (ALL): Added support for Read/Write Multiple Registers
function (0x17). The implementation simply makes two callbacks
to the eMBRegHoldingCB function where first the values are
written and then the other register values are read.
- FEATURE (ALL): Added some tips on reducing memory requirements
with the protocol stack.
2006-10-30 (REL_1_0_5) Christian Walter <wolti@sil.at>:
Notes: eMBDisable and eMBClose can now be called multiple times
which makes shutdown of the protocol stack easier.
Fixed bug in RTU state machine where we switched from the
error state immediately to the idle state. Correct behaviour
would be to wait till the end of frame.
Added new STR71X GCC port which uses only freely available tools
like GNU ARM, OpenOCD (Wiggler) and GDB.
Detailed notes:
- FEATURE (STR71X): Added GCC standalone port which does not
depend on the Rowley Crosswork tools.
- FEATURE (ALL): eMBDisable can now be called multiple times
and returns MB_ENOERR in case is was already disabled.
eMBClose also supports beeing called multiple times in
which pvMBFrameCloseCur( ) is called when the protocol stack
is in state STATE_DISABLED.
- BUG (RTU): Fixed bug in xMBRTUReceiveFSM where the error
state is immediately left because of a missing break. Instead
we should wait till the damaged frame is finished.
2006-10-11 (REL_1_0_4) Christian Walter <wolti@sil.at>:
Notes: Fixed bug when more than 255 coils are requested. Fixed bug in
Linux/Cygwin port when not all bytes could be written by the first
call to write. Added support for removing previously registered
function handlers.
Detailed notes:
- BUG (ALL): mbfunccoils contained a bug which limited the amount
of coils to read to 255.
- BUG (LINUX): prvbMBPortSerialWrite contained a bug in the loop
which writes the RTU/ASCII frame to the serial file descriptor.
If not all bytes where written in the first call or write was
interrupted the sent frame is corrupted.
- FEATURE (ALL): eMBRegisterCB now supports NULL as handler
argument in which case a previously registered function
handler is deregistered from the protocol stack.
2006-09-27 (REL_1_0_3) Christian Walter <wolti@sil.at>:
Notes: Added new functions to support registering of custom callback
handlers. This makes it possible to implement new Modbus function
codes without touching the protocol stack.
New port for ATMega128 added. Thanks to Richard C Sandoz Jr. for
the patches.
Detailed notes:
- FEATURE (ALL): Added support for registering new functions handlers
with eMBRegisterCB.
- FEATURE (AVR): Added patches from Richard C Sandoz Jr. for ATMega128
2006-09-06 (REL_1_0_2) Christian Walter <wolti@sil.at>:
Notes: Fixed bug in FreeRTOS porting layer for STR71X/lwIP target where
memory is not freed in the sys_arch_thread_remove function.
Synched MCF5235TCP port with the FreeRTOS/lwIP port for the STR71X.
Detailed notes:
- BUG (STR71XTCP): Sys_arch_thread_remove did not free the memory from
the TCB.
- BUG (STR71XTCP): Unnecessary call to vTaskSuspendAll removed.
- BUG (STR71XTCP): Bug with counting variable. The first to lwIP tasks
got the same name (lwIP0).
- FEATURE (MCF5235TCP): Enhanced functions from the STR71X/lwIP port
merged into the Coldfire port.
2006-09-04 (REL_1_0_1) Christian Walter <wolti@sil.at>:
Notes: Fixed bug in serial driver for STR71x target when the ring buffer
overflows.
Detailed notes:
- BUG (STR71XTCP): Under high load the ring buffer in the serial driver
functions might overflow. There was an error with counting the number
of received characters which corrupted received frames.
Now receiver correctly recovers in case of dropped bytes.
2006-09-04 (REL_1_0) Christian Walter <wolti@sil.at>:
Notes: Added support for ATmega8, ATmega16, ATmega32, ATmega169 and
RS485 drivers in the AVR support. Special thanks to Tran Minh Hoang
for his contribution.
Added a new lwIP port for the STR71X target which uses one serial
interface for a PPP connection. This can be used for remote Modbus/TCP
devices in combination with a Modem (E.g. GPRS or Analog).
Detailed notes:
- FEATURES (AVR): Integrated patches from Tran Minh Hoang to support the
ATmega8, ATmega16, ATmega32, ATmega169 controllers.
- FEATURES (AVR): Added support for RS485 drivers in the AVR code. The
example supports the DS76176.
- FEATURES (STR71XTCP): implemented function in STR71X/lwIP porting layer
to remove running tasks.
- FEATURES (STR71XTCP): added new thread creation function in STR71X/lwIP
porting layer which allows specifing the stack size.
- BUGS (STR71XTCP): pppOpen defined in ppp.c does not check the return
value of sys_thread_new. If task creation fails the system crashes.
- BUGS (STR71XTCP): pppMain must not return - Instead it should remove
its task from the scheduler.
2006-08-30 (REL_9) Christian Walter <wolti@sil.at>:
Notes: Added lwIP port for the MCF5235 target. The lwIP part is
generic and therefore FreeModbus now works on any target with
lwIP support.
Detailed notes:
- FEATURES: Incoperated MCF5235 FreeRTOS/lwIP port done by the
author in this project.
- FEATURES: Added lwIP port for FreeModbus
- FEATURES: Added demo application for FreeModbus and lwIP.
2006-08-22 (REL_0_82) Christian Walter <wolti@sil.at>
Notes: Fixed bug with Modbus ASCII support
Detailed notes:
- BUG: During the last upgrade an error was introduced in the
initialization code of Modbus ASCII and therefore ASCII
support was broken. The bug is fixed now and was tested with
the Win32 port.
2006-08-22 (REL_0_81) Christian Walter <wolti@sil.at>
Notes: Added porting guide
Detailed notes:
- OTHER: Added a new porting guide to the documentation.
- OTHER: Added a empty example for new ports to the project as a
starting point.
2006-08-01 (REL_0_8) Christian Walter <wolti@sil.at>
Notes: Added Linux RTU/ASCII port.
Detailed notes:
- FEATURES: Added a new Linux RTU/ASCII port. The port should work
on any Linux distribution and it should be possible to run it
on uCLinux.
2006-06-26 (REL_0_7) Christian Walter <wolti@sil.at>
Notes: Changed the WIN32 serial port to better fit into the design.
Detailed notes:
- OTHER: Design of the WIN32 serial port changed. The polling function
for the serial device are now called from the event loop.
- OTHER: Debugging uses the same interface as the WIN32/TCP port.
2006-06-25 Christian Walter <wolti@sil.at>
Notes: Initial work on a Modbus/TCP port is available. The port includes
an example for a Win32 port which uses the Winsock API.
Detailed notes:
- FEATURES: added required functions to core protocol stack to support
a Modbus/TCP implementation.
- FEATURES: added a Win32 port for the Modbus/TCP core. The port is
currently limited to one concurrent client.
- OTHER: The implementation of eMBClose to shutdown the protocol stack
was changed to unify it with the new Modbus/TCP code.
-
2006-06-18 Christian Walter <wolti@sil.at>
Detailed notes:
- OTHER: while working on the Win32 port some line feeds got
wrong. Also some source files used tabs instead of spaces.
- OTHER: prototypes for xMBUtilSetBits and xMBUtilGetBits fixed.
usNBits should be ucNBits by convention.
2006-06-17 Christian Walter <wolti@sil.at>
Notes: Fixed various bugs with the Win32 port
Detailed notes:
- FEATURES: implement shutdown functionality for protocol stack.
- FEATURES: protocol stack can be enabled and disabled during runtime.
- FEATURES: interface functions now do more error checking. For
example if eMBPool is called in an uninitialized state.
- FEATURES: extended Win32 demo application to use the new features.
- BUG: fixed bug in Win32 demo for ASCII mode.
2006-06-16 Christian Walter <wolti@sil.at>
Notes: The new version includes a new port for the
Win32 platform
Detailed notes:
- FEATURES: added Win32 platform
2006-05-14 Christian Walter <wolti@sil.at>
Notes: The new version includes a new port for the
Freescale MCF5235 processor.
Detailed notes:
- FEATURES: added new MCF5235 port.
- OTHER: fixed some missing code headers.
2006-05-01 Christian Walter <wolti@sil.at>
Notes: This version removes the t1.5 timers from the Modbus RTU
implementation because no one actually uses it and the CPU
load is very high. T
In addition some documentation cleanups has been done and the
ARM demo has been updated.
Detailed notes:
- FEATURES: the t1.5 timeout has been removed. Therefore only
one timer is required.
- BUG: the ARM demo project missed some files in the project
workspace and did not compile cleanly
2006-02-28 Christian Walter <wolti@sil.at>
Notes: This version includes support for two new command
(write multiple coils, read discrete input)
Detailed notes:
- BUG: some function used the wrong data types
- FEATURES: added support for write multiple coils function.
- FEATURES: added support for read discrete input.
- OTHER: some code cleanups with lint tool.
2006-02-28 Christian Walter <wolti@sil.at>
Notes: The new version 0.31 adds support for reading and writing the
coil registers and add some bug fixes.
Detailed notes:
- BUG: fixed bug with to small modbus requests being ignored.
- FEATURES: added support for write single coil function.
- FEATURES: added support for working with byte packed bit fields
to support coils and discrete inputs better.
- API: API for set slave id functions changed.
2006-02-26 Christian Walter <wolti@sil.at>
Notes: First public release which includes an ARM and AVR port.

View File

@ -0,0 +1,26 @@
Copyright (c) 2006 Christian Walter <wolti@sil.at>
Copyright (c) 2013-2019 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.

View File

@ -0,0 +1,3 @@
SRC_DIR := modbus port samples
include $(KERNEL_ROOT)/compiler.mk

View File

@ -0,0 +1,307 @@
# Freemodbus
[中文页](README_ZH.md) | English
## Introduction
This is the Freemodbus protocol stack ported by armink. Support the functions of the master and slave at the same time.
FreeModbus is an open source Modbus protocol stack, but only the slave is open source, and the host source code is **charged**. At the same time, no better open source Modbus host protocol stack was found on the Internet, so this FreeModbus protocol stack supporting host mode was developed. This version of FreeModbus has been changed to V1.6 and features are as follows:
- The newly added host source code is consistent with the style and interface of the original slave;
- Support the host and slave to run in the same protocol stack;
- Support real-time operating system and bare metal transplantation;
- Provide a variety of request modes for applications, users can choose blocking or non-blocking mode, custom timeout time, etc., to facilitate flexible calls at the application layer;
- Support all common Modbus methods.
### File structure
| Source File | Description |
| --------------------------------------------- | ----------------------------------------------- |
| FreeModbus\modbus\mb.c | Provides Modbus slave settings and polling related interfaces for the application layer |
| FreeModbus\modbus\mb_m.c | Provides Modbus host settings and polling related interfaces for the application layer |
| FreeModbus\modbus\ascii\mbascii.c | ASCII mode settings and state machine |
| FreeModbus\modbus\functions\mbfunccoils.c | Slave coil related functions |
| FreeModbus\modbus\functions\mbfunccoils_m.c | Host coil related functions |
| FreeModbus\modbus\functions\mbfuncdisc.c | Slave Discrete Input Related Functions |
| FreeModbus\modbus\functions\mbfuncdisc_m.c | Discrete input related functions of the host |
| FreeModbus\modbus\functions\mbfuncholding.c | Slave holding register related functions |
| FreeModbus\modbus\functions\mbfuncholding_m.c | Host holding register related functions |
| FreeModbus\modbus\functions\mbfuncinput.c | Slave input register related functions |
| FreeModbus\modbus\functions\mbfuncinput_m.c | Host input register related functions |
| FreeModbus\modbus\functions\mbfuncother.c | Other Modbus functions |
| FreeModbus\modbus\functions\mbutils.c | Some small tools that need to be used in the protocol stack |
| FreeModbus\modbus\rtu\mbcrc.c | CRC check function |
| FreeModbus\modbus\rtu\mbrtu.c | Slave RTU mode settings and state machine |
| FreeModbus\modbus\rtu\mbrtu_m.c | Host RTU mode settings and state machine |
| FreeModbus\modbus\tcp\mbtcp.c | TCP mode settings and state machine |
| FreeModbus\port\port.c | Implement hardware porting part of the interface |
| FreeModbus\port\portevent.c | Implement slave event porting interface |
| FreeModbus\port\portevent_m.c | Implement host event and error handling porting interface |
| FreeModbus\port\portserial.c | Slave port porting |
| FreeModbus\port\portserial_m.c | Host serial port porting |
| FreeModbus\port\porttimer.c | Slave timer porting |
| FreeModbus\port\porttimer_m.c | Host timer porting |
| FreeModbus\port\user_mb_app.c | Define slave data buffer, realize the callback interface of slave Modbus function |
| FreeModbus\port\user_mb_app_m.c | Define host data buffer, realize the callback interface of host Modbus function |
| FreeModbus\samples\sample_mb_master.c | Sample code for host use |
| FreeModbus\samples\sample_mb_slave.c | Slave use sample code |
| FreeModbus\samples\README.md | Sample code description document |
> Note: All files with the _m suffix are the files that must be used in the master mode. If the slave mode is used, these files are not required.
### License
The Freemodbus software package complies with the BSD license, see the `LICENSE` file for details.
### Dependence
- RT_Thread UART device
## method of obtaining
To use the Freemodbus software package, you need to select it in the RT-Thread package manager. The specific path is as follows:
```
RT-Thread online packages
IoT-internet of things --->
[*] FreeModbus: Modbus master and slave stack --->
[*] Master mode --->
[*] Slave mode --->
```
Finally, let RT-Thread's package manager automatically update, or use the `pkgs --update` command to update the package to the BSP.
## Instructions
### Data buffer
The location defined by the data buffer is at the top of the `FreeModbus\port\user_mb_app_m.c` file, with a total of **4** data types. By default, FreeModbus slaves use **one-dimensional array** as the data structure of the buffer area. The host can store the data of all slaves in the network, so the host uses **two-dimensional array** to store all slave node data. The column number of the two-dimensional array represents the register, coil and discrete address, and the row number represents the slave node ID, but it needs to be reduced by one. For example, `usMRegHoldBuf[2][1]` means the slave ID is 3, and the register address is maintained The slave data is 1.
### Modbus data processing callback interface
Modbus has 4 different data types in total, and all Modbus functions operate around these data types. Since different user data buffer structures may be different, the corresponding Modbus data processing methods are also different, so users need to customize the operations corresponding to each data type according to their own data buffer structure. All Modbus data processing callback interfaces are as follows:
| Interface | Function description |
| ---------------------- | ------------------ |
| eMBMasterRegInputCB | Input register callback interface |
| eMBMasterRegHoldingCB | Holding register callback interface |
| eMBMasterRegCoilsCB | Coil callback interface |
| eMBMasterRegDiscreteCB | Discrete input callback interface |
> For the data buffer structure in the form of an array, the source code has already been transplanted and can be used directly.
### Initial configuration process
All configuration parameters of this protocol stack are located in `FreeModbus\modbus\include\mbconfig.h`, currently the protocol stack supports two modes of master and slave, and supports **both modes to be turned on at the same time**. The slave supports Modbus RTU, Modbus ASCII and Modbus TCP 3 modes, and the master now only supports the commonly used **Modbus RTU** mode. In the process of using the master, the user needs to configure the broadcast conversion delay time, command response timeout time and the number of slaves. It should be noted that the current protocol stack only supports continuous slave addresses, and the starting address starts from 1**.
### Normal use process
1. Call the `eMBMasterInit` method to initialize the Modbus host protocol stack, and some hardware related to the host is initialized at this time
2. Call the `eMBMasterEnable` method to start the Modbus master
3. By calling the `eMBMasterPoll` method in thread or timer polling, the polling cycle determines the response time of the command.
4. Call the host to request the API method, set a certain request timeout period, and will not return until the method has a result. If the method is executed successfully and the command is a read command, you can obtain the latest slave data by viewing the data buffer of the Modbus master.
> For specific usage, please refer to the sample code in the `/samples` directory. Debugging the Modbus master-slave program can be debugged with Modbus Poll and Modbus slave software on the PC.
### Exception handling process
Exception handling mainly occurs during the normal use of the host. All the error codes of the host request API have been described at the beginning of Chapter 3. For these error codes, users need to complete different actions according to their own product features. It is recommended that users encapsulate and implement the retransmission mechanism of the host request method. This implementation is more flexible. Generally, retransmission is required when receiving frame data errors and command response timeout error codes. The number of retransmissions is automatically increased by one. If the set value is exceeded, the slave is considered to be offline, and all subsequent commands sent to this slave are intercepted in advance; if the second retransmission command response is successful, **automatically cleared** the slave retransmits frequency. All the above functions can be realized by using the host request method or using the callback interface in `FreeModbus\port\portevent_m.c`, and users can choose flexibly according to their needs.
## API detailed
The Modbus master is very different from the slave in the use process. The slave needs to passively wait for the request of the master, while the master actively sends out the request and receives and processes the response from the slave. When the host sends a broadcast request, the slave does not need to return a response, so the broadcast request is suitable for the master's write slave data command, not suitable for the read slave data command. The return value format of all methods in the host request API is the same, and the meaning of the return value is as follows.
| Return value | Description |
| ------------------ | ------------------------------------------- |
| MB_MRE_NO_ERR | Normal, no error |
| MB_MRE_NO_REG | Register, coil or discrete input address error |
| MB_MRE_ILL_ARG | Incorrect input parameter format |
| MB_MRE_REV_DATA | Receive data error |
| MB_MRE_TIMEDOUT | Response timed out. The host did not receive the response from the slave within the set time. |
| MB_MRE_MASTER_BUSY | The host is busy. The request was not sent within the set time. |
| MB_MRE_EXE_FUN | After the host receives the response, an error occurs when executing the Modbus method (function). |
> All host request methods are **thread safe** and **blocking mode**. During use, as long as the host resource is not obtained within the set timeout period, it will return that the host is busy; if the host resource is obtained within the set timeout period, it must wait for the request result before returning.
### Write a single holding register
Write data to a holding register of the slave
```
eMBMasterReqErrCode eMBMasterReqWriteHoldingRegister( UCHAR ucSndAddr,
USHORT usRegAddr,
USHORT usRegData,
LONG lTimeOut );
```
| Parameters | Description |
| --------- | ----------------------------------------------------------- |
| ucSndAddr | Requested slave address, 0 means broadcast. |
| usRegAddr | Write register address |
| usRegData | Write register data |
| lTimeOut | Request timeout time. To support permanent waiting, just use the permanent waiting parameter of the operating system. |
### Write multiple holding registers
Write data to multiple holding registers of the slave.
```
eMBMasterReqErrCode eMBMasterReqWriteMultipleHoldingRegister( UCHAR ucSndAddr,
USHORT usRegAddr,
USHORT usNRegs,
USHORT * pusDataBuffer,
LONG lTimeOut)
```
| Parameters | Description |
| ------------- | ----------------------------------------------------------- |
| ucSndAddr | Requested slave address, 0 means broadcast. |
| usRegAddr | Start address of write register |
| usNRegs | Total number of write registers |
| pusDataBuffer | Write register data |
| lTimeOut | Request timeout time. To support permanent waiting, just use the permanent waiting parameter of the operating system. |
### Read multiple holding registers
Read data in multiple holding registers
```
eMBMasterReqErrCode eMBMasterReqReadHoldingRegister( UCHAR ucSndAddr,
USHORT usRegAddr,
USHORT usNRegs,
LONG lTimeOut );
```
| Parameters | Description |
| --------- | ----------------------------------------------------------- |
| ucSndAddr | Requested slave address, 0 means broadcast. |
| usRegAddr | Read register address |
| usRegData | Number of read registers |
| lTimeOut | Request timeout time. To support permanent waiting, just use the permanent waiting parameter of the operating system. |
### Read and write multiple holding registers
Read multiple registers first, and then write multiple registers.
```
eMBMasterReqErrCode eMBMasterReqReadWriteMultipleHoldingRegister( UCHAR ucSndAddr,
USHORT usReadRegAddr,
USHORT usNReadRegs,
USHORT * pusDataBuffer,
USHORT usWriteRegAddr,
USHORT usNWriteRegs,
LONG lTimeOut)
```
| Parameters | Description |
| -------------- | ----------------------------------------------------------- |
| ucSndAddr | Requested slave address, 0 means broadcast. |
| usReadRegAddr | Read register address |
| usNReadRegs | Number of read registers |
| pusDataBuffer | Write register data |
| usWriteRegAddr | Write register address |
| usNWriteRegs | Number of write registers |
| lTimeOut | Request timeout time. To support permanent waiting, just use the permanent waiting parameter of the operating system. |
### Read multiple input registers
Read data in multiple input registers
```
eMBMasterReqErrCode eMBMasterReqReadInputRegister( UCHAR ucSndAddr,
USHORT usRegAddr,
USHORT usNRegs,
LONG lTimeOut );
```
| Parameters | Description |
| --------- | ----------------------------------------------------------- |
| ucSndAddr | Requested slave address, 0 means broadcast. |
| usRegAddr | Read register address |
| usRegData | Number of read registers |
| lTimeOut | Request timeout time. To support permanent waiting, just use the permanent waiting parameter of the operating system. |
### Write a single coil
Write data to a coil of the slave
```
eMBMasterReqErrCode eMBMasterReqWriteCoil( UCHAR ucSndAddr,
USHORT usCoilAddr,
USHORT usCoilData,
LONG lTimeOut)
```
| Parameters | Description |
| ---------- | ----------------------------------------------------------- |
| ucSndAddr | Requested slave address, 0 means broadcast. |
| usCoilAddr | Write the address of the coil |
| usCoilData | Number of write coils |
| lTimeOut | Request timeout time. To support permanent waiting, just use the permanent waiting parameter of the operating system. |
### Write multiple coils
Write data to multiple coils of the slave.
```
eMBMasterReqErrCode eMBMasterReqWriteMultipleCoils( UCHAR ucSndAddr,
USHORT usCoilAddr,
USHORT usNCoils,
UCHAR * pucDataBuffer,
LONG lTimeOut)
```
| Parameters | Description |
| ------------- | ----------------------------------------------------------- |
| ucSndAddr | Requested slave address, 0 means broadcast. |
| usCoilAddr | Write the start address of the coil |
| usNCoils | Total number of write coils |
| pucDataBuffer | Write coil data |
| lTimeOut | Request timeout time. To support permanent waiting, just use the permanent waiting parameter of the operating system. |
### Read multiple coils
Read data from multiple coils
```
eMBMasterReqErrCode eMBMasterReqReadCoils( UCHAR ucSndAddr,
USHORT usCoilAddr,
USHORT usNCoils,
LONG lTimeOut)
```
| Parameters | Description |
| ---------- | ------------------------------------------------------------ |
| ucSndAddr | Requested slave address, 0 means broadcast. |
| usCoilAddr | Read the address of the coil |
| usNCoils | Number of reading coils |
| lTimeOut | Request timeout time. To support permanent waiting, just use the permanent waiting parameter of the operating system. |
### Read multiple discrete inputs
Read data from multiple discrete inputs
```
eMBMasterReqErrCode eMBMasterReqReadDiscreteInputs( UCHAR ucSndAddr,
USHORT usDiscreteAddr,
USHORT usNDiscreteIn,
LONG lTimeOut)
```
| Parameters | Description |
| -------------- | ------------------------------------------------------------ |
| ucSndAddr | Requested slave address, 0 means broadcast. |
| usDiscreteAddr | Read the address of discrete input |
| usNDiscreteIn | Read the number of discrete inputs |
| lTimeOut | Request timeout time. To support permanent waiting, just use the permanent waiting parameter of the operating system. |
## Precautions
- The slave supports Modbus RTU, Modbus ASCII and Modbus TCP 3 modes. The master now only supports the commonly used **Modbus RTU** mode.
- Currently the protocol stack only supports **continuous slave address**, and the starting address **starts from 1**.
## Contact information
- Maintenance: RT-Thread development team and community developers
- Homepage: <https://github.com/RT-Thread-packages/freemodbus>

View File

@ -0,0 +1,308 @@
# Freemodbus
中文页 | [English](README.md)
## 简介
这是 armink 大神移植的 Freemodbus 协议栈。同时支持主机和从机的功能。
FreeModbus 是一款开源的 Modbus 协议栈,但是只有从机开源,主机源码是需要**收费**的。同时网上也没有发现比较好的开源的 Modbus 主机协议栈,所以才开发这款支持主机模式的 FreeModbus 协议栈。本版 FreeModbus版本号更改为V1.6,特性如下:
- 新增加的主机源码与原有从机的风格及接口保持一致;
- 支持主机与从机在同一协议栈运行;
- 支持实时操作系统及裸机移植;
- 为应用提供多种请求模式,用户可以选择阻塞还是非阻塞模式,自定义超时时间等,方便应用层灵活调用;
- 支持所有常用的Modbus方法。
### 文件结构
| 源文件 | 描述 |
| --------------------------------------------- | ------------------------------------------------ |
| FreeModbus\modbus\mb.c | 给应用层提供Modbus从机设置及轮询相关接口 |
| FreeModbus\modbus\mb_m.c | 给应用层提供Modbus主机设置及轮询相关接口 |
| FreeModbus\modbus\ascii\mbascii.c | ASCII模式设置及其状态机 |
| FreeModbus\modbus\functions\mbfunccoils.c | 从机线圈相关功能 |
| FreeModbus\modbus\functions\mbfunccoils_m.c | 主机线圈相关功能 |
| FreeModbus\modbus\functions\mbfuncdisc.c | 从机离散输入相关功能 |
| FreeModbus\modbus\functions\mbfuncdisc_m.c | 主机离散输入相关功能 |
| FreeModbus\modbus\functions\mbfuncholding.c | 从机保持寄存器相关功能 |
| FreeModbus\modbus\functions\mbfuncholding_m.c | 主机保持寄存器相关功能 |
| FreeModbus\modbus\functions\mbfuncinput.c | 从机输入寄存器相关功能 |
| FreeModbus\modbus\functions\mbfuncinput_m.c | 主机输入寄存器相关功能 |
| FreeModbus\modbus\functions\mbfuncother.c | 其余Modbus功能 |
| FreeModbus\modbus\functions\mbutils.c | 一些协议栈中需要用到的小工具 |
| FreeModbus\modbus\rtu\mbcrc.c | CRC校验功能 |
| FreeModbus\modbus\rtu\mbrtu.c | 从机RTU模式设置及其状态机 |
| FreeModbus\modbus\rtu\mbrtu_m.c | 主机RTU模式设置及其状态机 |
| FreeModbus\modbus\tcp\mbtcp.c | TCP模式设置及其状态机 |
| FreeModbus\port\port.c | 实现硬件移植部分接口 |
| FreeModbus\port\portevent.c | 实现从机事件移植接口 |
| FreeModbus\port\portevent_m.c | 实现主机事件及错误处理移植接口 |
| FreeModbus\port\portserial.c | 从机串口移植 |
| FreeModbus\port\portserial_m.c | 主机串口移植 |
| FreeModbus\port\porttimer.c | 从机定时器移植 |
| FreeModbus\port\porttimer_m.c | 主机定时器移植 |
| FreeModbus\port\user_mb_app.c | 定义从机数据缓冲区实现从机Modbus功能的回调接口 |
| FreeModbus\port\user_mb_app_m.c | 定义主机数据缓冲区实现主机Modbus功能的回调接口 |
| FreeModbus\samples\sample_mb_master.c | 主机使用示例代码 |
| FreeModbus\samples\sample_mb_slave.c | 从机使用示例代码 |
| FreeModbus\samples\README.md | 示例代码说明文档 |
> 注所有带_m后缀的文件为主机模式下必须使用的文件如使用从机模式则无需这些文件。
### 许可证
Freemodbus 软件包遵循 BSD 许可,详见 `LICENSE` 文件。
### 依赖
- RT_Thread UART 设备
- XiUOS UART 设备
## 获取方式
使用 Freemodbus 软件包 需要在 RT-Thread 的包管理器中选择它,具体路径如下:
```
RT-Thread online packages
IoT - internet of things --->
[*] FreeModbus: Modbus master and slave stack --->
[*] Master mode --->
[*] Slave mode --->
```
最后让 RT-Thread 的包管理器自动更新,或者使用 `pkgs --update` 命令更新包到 BSP 中。
## 使用方法
### 数据缓冲区
数据缓冲区定义的位置位于 `FreeModbus\port\user_mb_app_m.c` 文件顶部,共计 **4种** 数据类型。 FreeModbus从机默认使用 **一维数组** 作为缓存区数据结构,主机可以存储所有网内从机的数据,所以主机采用 **二维数组** 对所有从机节点数据进行存储。二维数组的列号代表寄存器、线圈及离散量地址行号代表从机节点ID但需要做减一处理例如`usMRegHoldBuf[2][1]`代表从机ID为 3保持寄存器地址为 1 的从机数据。
### Modbus 数据处理回调接口
Modbus 一共有4种不同的数据类型所有的 Modbus 功能都围绕这些数据类型进行操作。由于不同的用户数据缓冲区结构可能有所不同,那么对应的 Modbus 数据处理方式也就存在差异,所以用户需要把每种数据类型对应的操作,按照自己的数据缓冲区结构进行定制实现。 所有的 Modbus 数据处理回调接口如下:
| 接口 | 功能描述 |
| ---------------------- | ------------------ |
| eMBMasterRegInputCB | 输入寄存器回调接口 |
| eMBMasterRegHoldingCB | 保持寄存器回调接口 |
| eMBMasterRegCoilsCB | 线圈回调接口 |
| eMBMasterRegDiscreteCB | 离散输入回调接口 |
> 对于数组形式的数据缓冲区结构,源码中已经做好了移植,直接使用即可。
### 初始化配置流程
本协议栈所有配置参数都位于`FreeModbus\modbus\include\mbconfig.h`,目前协议栈支持主机及从机两种模式,并且支持**两种模式同时开启**。从机支持Modbus RTU 、Modbus ASCII 及Modbus TCP 3种模式主机现在只支持常用的**Modbus RTU**模式。在使用主机的过程中,用户需要对广播的转换延时时间、命令响应超时时间及从机数量做以配置。需要注意的是,目前协议栈只支持**从机地址连续**,并且起始地址**从1开始**。
### 正常使用流程
1. 调用`eMBMasterInit`方法初始化Modbus主机协议栈主机涉及到的一些硬件就在这个时候做了初始化
2. 调用`eMBMasterEnable`方法启动Modbus主机
3. 通过在线程或者定时器轮询调用`eMBMasterPoll`方法,轮询周期决定了命令的响应时间。
4. 调用主机请求API方法设定一定的请求超时时间直到方法有结果后才会返回。如果方法执行成功并且命令是读命令可以通过查看Modbus主机的数据缓冲区获取最新从机数据。
> 具体的使用方法,可以参考 `/samples` 目录下的示例代码。调试 Modbus 的主从机程序可以在 PC 上使用 Modbus Poll 和 Modbus slave 软件配合调试。
### 异常处理流程
异常处理主要出现在主机正常使用过程中所有的主机请求API的错误码都在第三章开头已经做以描述针对的这些错误码用户需要根据自己的产品特征去完成不同的动作。建议用户自己封装实现主机请求方法的重发机制这样实现方式比较灵活一般是在接收到帧数据出错及命令响应超时的错误码时需要重发重发次数自动加一如果重发次数超过设定值则认为从机掉线以后所有只要是发给这个从机命令都被提前拦截掉如果第二次重发命令响应成功则**自动清零**该从机重发次数。 上述所有功能可以利用主机请求方法或者使用`FreeModbus\port\portevent_m.c`中的回调接口来实现,用户可以根据自己的需求灵活选择。
## API 详解
Modbus 主机使用过程中与从机有很大不同,从机是需要被动等待主机请求,而主机则是主动发出请求,并接收处理从机响应。在主机发送广播请求的时候,从机不需要返回响应,所以广播请求适合主机的写从机数据命令,不适合读从机数据命令。 主机请求API中的所有方法的返回值格式都相同返回值意义如下。
| 返回值 | 描述 |
| ------------------ | -------------------------------------------- |
| MB_MRE_NO_ERR | 正常,没错误 |
| MB_MRE_NO_REG | 寄存器、线圈或离散输入地址出错 |
| MB_MRE_ILL_ARG | 入参格式有误 |
| MB_MRE_REV_DATA | 接收数据出错 |
| MB_MRE_TIMEDOUT | 响应超时。主机在设定的时间内未收到从机响应。 |
| MB_MRE_MASTER_BUSY | 主机忙。在设定的时间内,请求没有被发送。 |
| MB_MRE_EXE_FUN | 主机收到响应后执行Modbus方法功能出错。 |
> 所有的主机请求方法都是 **线程安全** 的也是 **阻塞模式** 的。在使用过程中,只要在设定的超时时间内没有得到主机资源,就会返回主机忙;如果在设定的超时时间内得到主机资源,那么必须等待得到请求结果后才会返回。
### 写单个保持寄存器
往从机某个保持寄存器中写入数据
```
eMBMasterReqErrCode eMBMasterReqWriteHoldingRegister( UCHAR ucSndAddr,
USHORT usRegAddr,
USHORT usRegData,
LONG lTimeOut );
```
| 参数 | 描述 |
| --------- | ------------------------------------------------------------ |
| ucSndAddr | 请求的从机地址0代表广播。 |
| usRegAddr | 写寄存器的地址 |
| usRegData | 写寄存器的数据 |
| lTimeOut | 请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。 |
### 写多个保持寄存器
往从机多个保持寄存器中写入数据。
```
eMBMasterReqErrCode eMBMasterReqWriteMultipleHoldingRegister( UCHAR ucSndAddr,
USHORT usRegAddr,
USHORT usNRegs,
USHORT * pusDataBuffer,
LONG lTimeOut )
```
| 参数 | 描述 |
| ------------- | ------------------------------------------------------------ |
| ucSndAddr | 请求的从机地址0代表广播。 |
| usRegAddr | 写寄存器的起始地址 |
| usNRegs | 写寄存器的总数 |
| pusDataBuffer | 写寄存器的数据 |
| lTimeOut | 请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。 |
### 读多个保持寄存器
读取多个保持寄存器中的数据
```
eMBMasterReqErrCode eMBMasterReqReadHoldingRegister( UCHAR ucSndAddr,
USHORT usRegAddr,
USHORT usNRegs,
LONG lTimeOut );
```
| 参数 | 描述 |
| --------- | ------------------------------------------------------------ |
| ucSndAddr | 请求的从机地址0代表广播。 |
| usRegAddr | 读寄存器的地址 |
| usRegData | 读寄存器的数量 |
| lTimeOut | 请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。 |
### 读写多个保持寄存器
先读多个寄存器,然后再写多个寄存器。
```
eMBMasterReqErrCode eMBMasterReqReadWriteMultipleHoldingRegister( UCHAR ucSndAddr,
USHORT usReadRegAddr,
USHORT usNReadRegs,
USHORT * pusDataBuffer,
USHORT usWriteRegAddr,
USHORT usNWriteRegs,
LONG lTimeOut )
```
| 参数 | 描述 |
| -------------- | ------------------------------------------------------------ |
| ucSndAddr | 请求的从机地址0代表广播。 |
| usReadRegAddr | 读寄存器的地址 |
| usNReadRegs | 读寄存器的数量 |
| pusDataBuffer | 写寄存器的数据 |
| usWriteRegAddr | 写寄存器的地址 |
| usNWriteRegs | 写寄存器的数量 |
| lTimeOut | 请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。 |
### 读多个输入寄存器
读取多个输入寄存器中的数据
```
eMBMasterReqErrCode eMBMasterReqReadInputRegister( UCHAR ucSndAddr,
USHORT usRegAddr,
USHORT usNRegs,
LONG lTimeOut );
```
| 参数 | 描述 |
| --------- | ------------------------------------------------------------ |
| ucSndAddr | 请求的从机地址0代表广播。 |
| usRegAddr | 读寄存器的地址 |
| usRegData | 读寄存器的数量 |
| lTimeOut | 请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。 |
### 写单个线圈
往从机某个线圈中写入数据
```
eMBMasterReqErrCode eMBMasterReqWriteCoil( UCHAR ucSndAddr,
USHORT usCoilAddr,
USHORT usCoilData,
LONG lTimeOut )
```
| 参数 | 描述 |
| ---------- | ------------------------------------------------------------ |
| ucSndAddr | 请求的从机地址0代表广播。 |
| usCoilAddr | 写线圈的地址 |
| usCoilData | 写线圈的数量 |
| lTimeOut | 请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。 |
### 写多个线圈
往从机多个线圈中写入数据。
```
eMBMasterReqErrCode eMBMasterReqWriteMultipleCoils( UCHAR ucSndAddr,
USHORT usCoilAddr,
USHORT usNCoils,
UCHAR * pucDataBuffer,
LONG lTimeOut)
```
| 参数 | 描述 |
| ------------- | ------------------------------------------------------------ |
| ucSndAddr | 请求的从机地址0代表广播。 |
| usCoilAddr | 写线圈的起始地址 |
| usNCoils | 写线圈的总数 |
| pucDataBuffer | 写线圈的数据 |
| lTimeOut | 请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。 |
### 读多个线圈
读取多个线圈中的数据
```
eMBMasterReqErrCode eMBMasterReqReadCoils( UCHAR ucSndAddr,
USHORT usCoilAddr,
USHORT usNCoils ,
LONG lTimeOut )
```
| 参数 | 描述 |
| ---------- | ------------------------------------------------------------ |
| ucSndAddr | 请求的从机地址0代表广播。 |
| usCoilAddr | 读线圈的地址 |
| usNCoils | 读线圈的数量 |
| lTimeOut | 请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。 |
### 读多个离散输入
读取多个离散输入中的数据
```
eMBMasterReqErrCode eMBMasterReqReadDiscreteInputs( UCHAR ucSndAddr,
USHORT usDiscreteAddr,
USHORT usNDiscreteIn,
LONG lTimeOut )
```
| 参数 | 描述 |
| -------------- | ------------------------------------------------------------ |
| ucSndAddr | 请求的从机地址0代表广播。 |
| usDiscreteAddr | 读离散输入的地址 |
| usNDiscreteIn | 读离散输入的数量 |
| lTimeOut | 请求超时时间。支持永久等待,使用操作系统的永久等待参数即可。 |
## 注意事项
- 从机支持Modbus RTU 、Modbus ASCII 及Modbus TCP 3种模式主机现在只支持常用的**Modbus RTU**模式。
- 目前协议栈只支持**从机地址连续**,并且起始地址**从1开始**。
## 联系方式
- 维护RT-Thread 开发团队及社区开发者
- 主页:<https://github.com/RT-Thread-packages/freemodbus>

View File

@ -0,0 +1,69 @@
Import('RTT_ROOT')
from building import *
src = Split("""
modbus/functions/mbfuncdiag.c
modbus/functions/mbutils.c
modbus/functions/mbfuncother.c
modbus/rtu/mbcrc.c
port/port.c
""")
master_rtu_src = Split("""
modbus/functions/mbfunccoils_m.c
modbus/functions/mbfuncdisc_m.c
modbus/functions/mbfuncholding_m.c
modbus/functions/mbfuncinput_m.c
modbus/rtu/mbrtu_m.c
modbus/mb_m.c
port/portevent_m.c
port/portserial_m.c
port/porttimer_m.c
port/user_mb_app_m.c
""")
slave_src = Split("""
modbus/functions/mbfunccoils.c
modbus/functions/mbfuncdisc.c
modbus/functions/mbfuncholding.c
modbus/functions/mbfuncinput.c
modbus/mb.c
port/portevent.c
port/portserial.c
port/porttcp.c
port/porttimer.c
port/user_mb_app.c
""")
# The set of source files associated with this SConscript file.
path = [GetCurrentDir() + '/modbus/include',
GetCurrentDir() + '/modbus/rtu',
GetCurrentDir() + '/modbus/ascii',
GetCurrentDir() + '/modbus/tcp',
GetCurrentDir() + '/port']
if GetDepend(['PKG_MODBUS_MASTER_RTU']):
src += master_rtu_src
if GetDepend(['PKG_MODBUS_SLAVE']):
src += slave_src
if GetDepend(['PKG_MODBUS_SLAVE_RTU']):
src += ['modbus/rtu/mbrtu.c']
if GetDepend(['PKG_MODBUS_SLAVE_ASCII']):
src += ['modbus/ascii/mbascii.c']
src += ['modbus/rtu/mbrtu.c']
if GetDepend(['PKG_MODBUS_SLAVE_TCP']):
src += ['modbus/tcp/mbtcp.c']
if GetDepend(['PKG_MODBUS_MASTER_SAMPLE']):
src += ['samples/sample_mb_master.c']
if GetDepend(['PKG_MODBUS_SLAVE_SAMPLE']):
src += ['samples/sample_mb_slave.c']
group = DefineGroup('FreeModbus', src, depend = ['PKG_USING_FREEMODBUS'], CPPPATH = path)
Return('group')

View File

@ -0,0 +1,26 @@
Copyright (c) 2006 Christian Walter <wolti@sil.at>
Copyright (c) 2013-2019 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.

View File

@ -0,0 +1,25 @@
SRC_DIR := functions
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_RTU),y)
SRC_DIR += rtu
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_RTU_MASTER),y)
SRC_FILES += mb_m.c
endif
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_RTU_SLAVE),y)
SRC_FILES += mb.c
endif
endif
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_TCP),y)
SRC_DIR += tcp
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_TCP_SLAVE),y)
SRC_FILES += mb.c
endif
endif
include $(KERNEL_ROOT)/compiler.mk

View File

@ -1,4 +1,4 @@
/*
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
* All rights reserved.
@ -25,6 +25,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbascii.c,v 1.15 2007/02/18 23:46:48 wolti Exp $
*/
/* ----------------------- System includes ----------------------------------*/
@ -43,7 +44,7 @@
#include "mbcrc.h"
#include "mbport.h"
#if MB_ASCII_ENABLED > 0
#if MB_SLAVE_ASCII_ENABLED > 0
/* ----------------------- Defines ------------------------------------------*/
#define MB_ASCII_DEFAULT_CR '\r' /*!< Default CR character for Modbus ASCII. */
@ -108,7 +109,7 @@ eMBASCIIInit( UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eP
{
eMBErrorCode eStatus = MB_ENOERR;
( void )ucSlaveAddress;
ENTER_CRITICAL_SECTION( );
ucMBLFCharacter = MB_ASCII_DEFAULT_LF;

View File

@ -1,4 +1,4 @@
/*
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
* All rights reserved.
@ -25,6 +25,7 @@
* (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
@ -34,7 +35,7 @@
PR_BEGIN_EXTERN_C
#endif
#if MB_ASCII_ENABLED > 0
#if MB_SLAVE_ASCII_ENABLED > 0
eMBErrorCode eMBASCIIInit( UCHAR slaveAddress, UCHAR ucPort,
ULONG ulBaudRate, eMBParity eParity );
void eMBASCIIStart( void );

View File

@ -0,0 +1,15 @@
SRC_FILES := mbfuncother.c mbutils.c mbfuncdiag.c
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_RTU_MASTER),y)
SRC_FILES += mbfunccoils_m.c mbfuncdisc_m.c mbfuncholding_m.c mbfuncinput_m.c
endif
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_RTU_SLAVE),y)
SRC_FILES += mbfunccoils.c mbfuncdisc.c mbfuncholding.c mbfuncinput.c
endif
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_TCP_SLAVE),y)
SRC_FILES += mbfunccoils.c mbfuncdisc.c mbfuncholding.c mbfuncinput.c
endif
include $(KERNEL_ROOT)/compiler.mk

View File

@ -1,4 +1,4 @@
/*
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
* All rights reserved.
@ -25,6 +25,7 @@
* (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 ----------------------------------*/
@ -85,7 +86,7 @@ eMBFuncReadCoils( UCHAR * pucFrame, USHORT * usLen )
usCoilCount |= ( USHORT )( 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.
* return Modbus illegal data value exception.
*/
if( ( usCoilCount >= 1 ) &&
( usCoilCount < MB_PDU_FUNC_READ_COILCNT_MAX ) )
@ -123,7 +124,7 @@ eMBFuncReadCoils( UCHAR * pucFrame, USHORT * usLen )
else
{
/* The response contains the function code, the starting address
* and the quantity of registers. We reuse the old values in the
* and the quantity of registers. We reuse the old values in the
* buffer because they are still valid. */
*usLen += ucNBytes;;
}
@ -141,6 +142,7 @@ eMBFuncReadCoils( UCHAR * pucFrame, USHORT * usLen )
}
return eStatus;
}
#endif
#if MB_FUNC_WRITE_COIL_ENABLED > 0
eMBException
@ -245,7 +247,7 @@ eMBFuncWriteMultipleCoils( UCHAR * pucFrame, USHORT * usLen )
else
{
/* The response contains the function code, the starting address
* and the quantity of registers. We reuse the old values in the
* 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;
}
@ -265,5 +267,3 @@ eMBFuncWriteMultipleCoils( UCHAR * pucFrame, USHORT * usLen )
}
#endif
#endif

View File

@ -0,0 +1,390 @@
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbfunccoils_m.c,v 1.60 2013/10/12 15:10:12 Armink Add Master Functions
*/
/* ----------------------- System includes ----------------------------------*/
#include "stdlib.h"
#include "string.h"
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mb_m.h"
#include "mbframe.h"
#include "mbproto.h"
#include "mbconfig.h"
/* ----------------------- Defines ------------------------------------------*/
#define MB_PDU_REQ_READ_ADDR_OFF ( MB_PDU_DATA_OFF + 0 )
#define MB_PDU_REQ_READ_COILCNT_OFF ( MB_PDU_DATA_OFF + 2 )
#define MB_PDU_REQ_READ_SIZE ( 4 )
#define MB_PDU_FUNC_READ_COILCNT_OFF ( MB_PDU_DATA_OFF + 0 )
#define MB_PDU_FUNC_READ_VALUES_OFF ( MB_PDU_DATA_OFF + 1 )
#define MB_PDU_FUNC_READ_SIZE_MIN ( 1 )
#define MB_PDU_REQ_WRITE_ADDR_OFF ( MB_PDU_DATA_OFF )
#define MB_PDU_REQ_WRITE_VALUE_OFF ( MB_PDU_DATA_OFF + 2 )
#define MB_PDU_REQ_WRITE_SIZE ( 4 )
#define MB_PDU_FUNC_WRITE_ADDR_OFF ( MB_PDU_DATA_OFF )
#define MB_PDU_FUNC_WRITE_VALUE_OFF ( MB_PDU_DATA_OFF + 2 )
#define MB_PDU_FUNC_WRITE_SIZE ( 4 )
#define MB_PDU_REQ_WRITE_MUL_ADDR_OFF ( MB_PDU_DATA_OFF )
#define MB_PDU_REQ_WRITE_MUL_COILCNT_OFF ( MB_PDU_DATA_OFF + 2 )
#define MB_PDU_REQ_WRITE_MUL_BYTECNT_OFF ( MB_PDU_DATA_OFF + 4 )
#define MB_PDU_REQ_WRITE_MUL_VALUES_OFF ( MB_PDU_DATA_OFF + 5 )
#define MB_PDU_REQ_WRITE_MUL_SIZE_MIN ( 5 )
#define MB_PDU_REQ_WRITE_MUL_COILCNT_MAX ( 0x07B0 )
#define MB_PDU_FUNC_WRITE_MUL_ADDR_OFF ( MB_PDU_DATA_OFF )
#define MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF ( MB_PDU_DATA_OFF + 2 )
#define MB_PDU_FUNC_WRITE_MUL_SIZE ( 5 )
/* ----------------------- Static functions ---------------------------------*/
eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
/* ----------------------- Start implementation -----------------------------*/
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
#if MB_FUNC_READ_COILS_ENABLED > 0
/**
* This function will request read coil.
*
* @param ucSndAddr salve address
* @param usCoilAddr coil start address
* @param usNCoils coil total number
* @param lTimeOut timeout (-1 will waiting forever)
*
* @return error code
*/
eMBMasterReqErrCode
eMBMasterReqReadCoils( UCHAR ucSndAddr, USHORT usCoilAddr, USHORT usNCoils ,LONG lTimeOut )
{
UCHAR *ucMBFrame;
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
else
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
vMBMasterSetDestAddress(ucSndAddr);
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_READ_COILS;
ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] = usCoilAddr >> 8;
ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] = usCoilAddr;
ucMBFrame[MB_PDU_REQ_READ_COILCNT_OFF ] = usNCoils >> 8;
ucMBFrame[MB_PDU_REQ_READ_COILCNT_OFF + 1] = usNCoils;
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE );
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
eErrStatus = eMBMasterWaitRequestFinish( );
}
return eErrStatus;
}
eMBException
eMBMasterFuncReadCoils( UCHAR * pucFrame, USHORT * usLen )
{
UCHAR *ucMBFrame;
USHORT usRegAddress;
USHORT usCoilCount;
UCHAR ucByteCount;
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
/* If this request is broadcast, and it's read mode. This request don't need execute. */
if ( xMBMasterRequestIsBroadcast() )
{
eStatus = MB_EX_NONE;
}
else if ( *usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READ_SIZE_MIN )
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
usRegAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] << 8 );
usRegAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] );
usRegAddress++;
usCoilCount = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_COILCNT_OFF] << 8 );
usCoilCount |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_COILCNT_OFF + 1] );
/* Test if the quantity of coils is a multiple of 8. If not last
* byte is only partially field with unused coils set to zero. */
if( ( usCoilCount & 0x0007 ) != 0 )
{
ucByteCount = ( UCHAR )( usCoilCount / 8 + 1 );
}
else
{
ucByteCount = ( UCHAR )( usCoilCount / 8 );
}
/* Check if the number of registers to read is valid. If not
* return Modbus illegal data value exception.
*/
if( ( usCoilCount >= 1 ) &&
( ucByteCount == pucFrame[MB_PDU_FUNC_READ_COILCNT_OFF] ) )
{
/* Make callback to fill the buffer. */
eRegStatus = eMBMasterRegCoilsCB( &pucFrame[MB_PDU_FUNC_READ_VALUES_OFF], usRegAddress, usCoilCount, MB_REG_READ );
/* If an error occured convert it into a Modbus exception. */
if( eRegStatus != MB_ENOERR )
{
eStatus = prveMBError2Exception( eRegStatus );
}
}
else
{
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
}
else
{
/* Can't be a valid read coil register request because the length
* is incorrect. */
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
return eStatus;
}
#endif
#if MB_FUNC_WRITE_COIL_ENABLED > 0
/**
* This function will request write one coil.
*
* @param ucSndAddr salve address
* @param usCoilAddr coil start address
* @param usCoilData data to be written
* @param lTimeOut timeout (-1 will waiting forever)
*
* @return error code
*
* @see eMBMasterReqWriteMultipleCoils
*/
eMBMasterReqErrCode
eMBMasterReqWriteCoil( UCHAR ucSndAddr, USHORT usCoilAddr, USHORT usCoilData, LONG lTimeOut )
{
UCHAR *ucMBFrame;
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
else if ( ( usCoilData != 0xFF00 ) && ( usCoilData != 0x0000 ) ) eErrStatus = MB_MRE_ILL_ARG;
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
else
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
vMBMasterSetDestAddress(ucSndAddr);
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_WRITE_SINGLE_COIL;
ucMBFrame[MB_PDU_REQ_WRITE_ADDR_OFF] = usCoilAddr >> 8;
ucMBFrame[MB_PDU_REQ_WRITE_ADDR_OFF + 1] = usCoilAddr;
ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF ] = usCoilData >> 8;
ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF + 1] = usCoilData;
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_SIZE );
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
eErrStatus = eMBMasterWaitRequestFinish( );
}
return eErrStatus;
}
eMBException
eMBMasterFuncWriteCoil( UCHAR * pucFrame, USHORT * usLen )
{
USHORT usRegAddress;
UCHAR ucBuf[2];
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
if( *usLen == ( MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN ) )
{
usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF] << 8 );
usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF + 1] );
usRegAddress++;
if( ( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF + 1] == 0x00 ) &&
( ( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0xFF ) ||
( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0x00 ) ) )
{
ucBuf[1] = 0;
if( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0xFF )
{
ucBuf[0] = 1;
}
else
{
ucBuf[0] = 0;
}
eRegStatus =
eMBMasterRegCoilsCB( &ucBuf[0], usRegAddress, 1, MB_REG_WRITE );
/* If an error occured convert it into a Modbus exception. */
if( eRegStatus != MB_ENOERR )
{
eStatus = prveMBError2Exception( eRegStatus );
}
}
else
{
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
}
else
{
/* Can't be a valid write coil register request because the length
* is incorrect. */
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
return eStatus;
}
#endif
#if MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED > 0
/**
* This function will request write multiple coils.
*
* @param ucSndAddr salve address
* @param usCoilAddr coil start address
* @param usNCoils coil total number
* @param usCoilData data to be written
* @param lTimeOut timeout (-1 will waiting forever)
*
* @return error code
*
* @see eMBMasterReqWriteCoil
*/
eMBMasterReqErrCode
eMBMasterReqWriteMultipleCoils( UCHAR ucSndAddr,
USHORT usCoilAddr, USHORT usNCoils, UCHAR * pucDataBuffer, LONG lTimeOut)
{
UCHAR *ucMBFrame;
USHORT usRegIndex = 0;
UCHAR ucByteCount;
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
else if ( usNCoils > MB_PDU_REQ_WRITE_MUL_COILCNT_MAX ) eErrStatus = MB_MRE_ILL_ARG;
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
else
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
vMBMasterSetDestAddress(ucSndAddr);
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_WRITE_MULTIPLE_COILS;
ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF] = usCoilAddr >> 8;
ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF + 1] = usCoilAddr;
ucMBFrame[MB_PDU_REQ_WRITE_MUL_COILCNT_OFF] = usNCoils >> 8;
ucMBFrame[MB_PDU_REQ_WRITE_MUL_COILCNT_OFF + 1] = usNCoils ;
if( ( usNCoils & 0x0007 ) != 0 )
{
ucByteCount = ( UCHAR )( usNCoils / 8 + 1 );
}
else
{
ucByteCount = ( UCHAR )( usNCoils / 8 );
}
ucMBFrame[MB_PDU_REQ_WRITE_MUL_BYTECNT_OFF] = ucByteCount;
ucMBFrame += MB_PDU_REQ_WRITE_MUL_VALUES_OFF;
while( ucByteCount > usRegIndex)
{
*ucMBFrame++ = pucDataBuffer[usRegIndex++];
}
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_MUL_SIZE_MIN + ucByteCount );
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
eErrStatus = eMBMasterWaitRequestFinish( );
}
return eErrStatus;
}
eMBException
eMBMasterFuncWriteMultipleCoils( UCHAR * pucFrame, USHORT * usLen )
{
USHORT usRegAddress;
USHORT usCoilCnt;
UCHAR ucByteCount;
UCHAR ucByteCountVerify;
UCHAR *ucMBFrame;
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
/* If this request is broadcast, the *usLen is not need check. */
if( ( *usLen == MB_PDU_FUNC_WRITE_MUL_SIZE ) || xMBMasterRequestIsBroadcast() )
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF] << 8 );
usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF + 1] );
usRegAddress++;
usCoilCnt = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF] << 8 );
usCoilCnt |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF + 1] );
ucByteCount = ucMBFrame[MB_PDU_REQ_WRITE_MUL_BYTECNT_OFF];
/* Compute the number of expected bytes in the request. */
if( ( usCoilCnt & 0x0007 ) != 0 )
{
ucByteCountVerify = ( UCHAR )( usCoilCnt / 8 + 1 );
}
else
{
ucByteCountVerify = ( UCHAR )( usCoilCnt / 8 );
}
if( ( usCoilCnt >= 1 ) && ( ucByteCountVerify == ucByteCount ) )
{
eRegStatus =
eMBMasterRegCoilsCB( &ucMBFrame[MB_PDU_REQ_WRITE_MUL_VALUES_OFF],
usRegAddress, usCoilCnt, MB_REG_WRITE );
/* If an error occured convert it into a Modbus exception. */
if( eRegStatus != MB_ENOERR )
{
eStatus = prveMBError2Exception( eRegStatus );
}
}
else
{
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
}
else
{
/* Can't be a valid write coil register request because the length
* is incorrect. */
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
return eStatus;
}
#endif
#endif

View File

@ -1,4 +1,4 @@
/*
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
* All rights reserved.
@ -25,4 +25,5 @@
* (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 $
*/

View File

@ -1,4 +1,4 @@
/*
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
* All rights reserved.
@ -74,7 +74,7 @@ eMBFuncReadDiscreteInputs( UCHAR * pucFrame, USHORT * usLen )
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.
* return Modbus illegal data value exception.
*/
if( ( usDiscreteCnt >= 1 ) &&
( usDiscreteCnt < MB_PDU_FUNC_READ_DISCCNT_MAX ) )
@ -111,7 +111,7 @@ eMBFuncReadDiscreteInputs( UCHAR * pucFrame, USHORT * usLen )
else
{
/* The response contains the function code, the starting address
* and the quantity of registers. We reuse the old values in the
* and the quantity of registers. We reuse the old values in the
* buffer because they are still valid. */
*usLen += ucNBytes;;
}

View File

@ -0,0 +1,162 @@
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbfuncdisc_m.c,v 1.60 2013/10/15 8:48:20 Armink Add Master Functions Exp $
*/
/* ----------------------- System includes ----------------------------------*/
#include "stdlib.h"
#include "string.h"
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mb_m.h"
#include "mbframe.h"
#include "mbproto.h"
#include "mbconfig.h"
/* ----------------------- Defines ------------------------------------------*/
#define MB_PDU_REQ_READ_ADDR_OFF ( MB_PDU_DATA_OFF + 0 )
#define MB_PDU_REQ_READ_DISCCNT_OFF ( MB_PDU_DATA_OFF + 2 )
#define MB_PDU_REQ_READ_SIZE ( 4 )
#define MB_PDU_FUNC_READ_DISCCNT_OFF ( MB_PDU_DATA_OFF + 0 )
#define MB_PDU_FUNC_READ_VALUES_OFF ( MB_PDU_DATA_OFF + 1 )
#define MB_PDU_FUNC_READ_SIZE_MIN ( 1 )
/* ----------------------- Static functions ---------------------------------*/
eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
/* ----------------------- Start implementation -----------------------------*/
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
#if MB_FUNC_READ_DISCRETE_INPUTS_ENABLED > 0
/**
* This function will request read discrete inputs.
*
* @param ucSndAddr salve address
* @param usDiscreteAddr discrete start address
* @param usNDiscreteIn discrete total number
* @param lTimeOut timeout (-1 will waiting forever)
*
* @return error code
*/
eMBMasterReqErrCode
eMBMasterReqReadDiscreteInputs( UCHAR ucSndAddr, USHORT usDiscreteAddr, USHORT usNDiscreteIn, LONG lTimeOut )
{
UCHAR *ucMBFrame;
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
else
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
vMBMasterSetDestAddress(ucSndAddr);
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_READ_DISCRETE_INPUTS;
ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] = usDiscreteAddr >> 8;
ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] = usDiscreteAddr;
ucMBFrame[MB_PDU_REQ_READ_DISCCNT_OFF ] = usNDiscreteIn >> 8;
ucMBFrame[MB_PDU_REQ_READ_DISCCNT_OFF + 1] = usNDiscreteIn;
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE );
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
eErrStatus = eMBMasterWaitRequestFinish( );
}
return eErrStatus;
}
eMBException
eMBMasterFuncReadDiscreteInputs( UCHAR * pucFrame, USHORT * usLen )
{
USHORT usRegAddress;
USHORT usDiscreteCnt;
UCHAR ucNBytes;
UCHAR *ucMBFrame;
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
/* If this request is broadcast, and it's read mode. This request don't need execute. */
if ( xMBMasterRequestIsBroadcast() )
{
eStatus = MB_EX_NONE;
}
else if( *usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READ_SIZE_MIN )
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
usRegAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] << 8 );
usRegAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] );
usRegAddress++;
usDiscreteCnt = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_DISCCNT_OFF] << 8 );
usDiscreteCnt |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_DISCCNT_OFF + 1] );
/* Test if the quantity of coils is a multiple of 8. If not last
* byte is only partially field with unused coils set to zero. */
if( ( usDiscreteCnt & 0x0007 ) != 0 )
{
ucNBytes = ( UCHAR )( usDiscreteCnt / 8 + 1 );
}
else
{
ucNBytes = ( UCHAR )( usDiscreteCnt / 8 );
}
/* Check if the number of registers to read is valid. If not
* return Modbus illegal data value exception.
*/
if ((usDiscreteCnt >= 1) && ucNBytes == pucFrame[MB_PDU_FUNC_READ_DISCCNT_OFF])
{
/* Make callback to fill the buffer. */
eRegStatus = eMBMasterRegDiscreteCB( &pucFrame[MB_PDU_FUNC_READ_VALUES_OFF], usRegAddress, usDiscreteCnt );
/* If an error occured convert it into a Modbus exception. */
if( eRegStatus != MB_ENOERR )
{
eStatus = prveMBError2Exception( eRegStatus );
}
}
else
{
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
}
else
{
/* Can't be a valid read coil register request because the length
* is incorrect. */
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
return eStatus;
}
#endif
#endif

View File

@ -1,4 +1,4 @@
/*
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
* All rights reserved.
@ -25,6 +25,7 @@
* (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 ----------------------------------*/
@ -182,10 +183,10 @@ eMBFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
usRegAddress++;
usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] << 8 );
usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );
usRegCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );
/* Check if the number of registers to read is valid. If not
* return Modbus illegal data value exception.
* return Modbus illegal data value exception.
*/
if( ( usRegCount >= 1 ) && ( usRegCount <= MB_PDU_FUNC_READ_REGCNT_MAX ) )
{

View File

@ -0,0 +1,455 @@
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbfuncholding_m.c,v 1.60 2013/09/02 14:13:40 Armink Add Master Functions Exp $
*/
/* ----------------------- System includes ----------------------------------*/
#include "stdlib.h"
#include "string.h"
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mb_m.h"
#include "mbframe.h"
#include "mbproto.h"
#include "mbconfig.h"
/* ----------------------- Defines ------------------------------------------*/
#define MB_PDU_REQ_READ_ADDR_OFF ( MB_PDU_DATA_OFF + 0 )
#define MB_PDU_REQ_READ_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 )
#define MB_PDU_REQ_READ_SIZE ( 4 )
#define MB_PDU_FUNC_READ_REGCNT_MAX ( 0x007D )
#define MB_PDU_FUNC_READ_BYTECNT_OFF ( MB_PDU_DATA_OFF + 0 )
#define MB_PDU_FUNC_READ_VALUES_OFF ( MB_PDU_DATA_OFF + 1 )
#define MB_PDU_FUNC_READ_SIZE_MIN ( 1 )
#define MB_PDU_REQ_WRITE_ADDR_OFF ( MB_PDU_DATA_OFF + 0)
#define MB_PDU_REQ_WRITE_VALUE_OFF ( MB_PDU_DATA_OFF + 2 )
#define MB_PDU_REQ_WRITE_SIZE ( 4 )
#define MB_PDU_FUNC_WRITE_ADDR_OFF ( MB_PDU_DATA_OFF + 0)
#define MB_PDU_FUNC_WRITE_VALUE_OFF ( MB_PDU_DATA_OFF + 2 )
#define MB_PDU_FUNC_WRITE_SIZE ( 4 )
#define MB_PDU_REQ_WRITE_MUL_ADDR_OFF ( MB_PDU_DATA_OFF + 0 )
#define MB_PDU_REQ_WRITE_MUL_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 )
#define MB_PDU_REQ_WRITE_MUL_BYTECNT_OFF ( MB_PDU_DATA_OFF + 4 )
#define MB_PDU_REQ_WRITE_MUL_VALUES_OFF ( MB_PDU_DATA_OFF + 5 )
#define MB_PDU_REQ_WRITE_MUL_SIZE_MIN ( 5 )
#define MB_PDU_REQ_WRITE_MUL_REGCNT_MAX ( 0x0078 )
#define MB_PDU_FUNC_WRITE_MUL_ADDR_OFF ( MB_PDU_DATA_OFF + 0 )
#define MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 )
#define MB_PDU_FUNC_WRITE_MUL_SIZE ( 4 )
#define MB_PDU_REQ_READWRITE_READ_ADDR_OFF ( MB_PDU_DATA_OFF + 0 )
#define MB_PDU_REQ_READWRITE_READ_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 )
#define MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF ( MB_PDU_DATA_OFF + 4 )
#define MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF ( MB_PDU_DATA_OFF + 6 )
#define MB_PDU_REQ_READWRITE_WRITE_BYTECNT_OFF ( MB_PDU_DATA_OFF + 8 )
#define MB_PDU_REQ_READWRITE_WRITE_VALUES_OFF ( MB_PDU_DATA_OFF + 9 )
#define MB_PDU_REQ_READWRITE_SIZE_MIN ( 9 )
#define MB_PDU_FUNC_READWRITE_READ_BYTECNT_OFF ( MB_PDU_DATA_OFF + 0 )
#define MB_PDU_FUNC_READWRITE_READ_VALUES_OFF ( MB_PDU_DATA_OFF + 1 )
#define MB_PDU_FUNC_READWRITE_SIZE_MIN ( 1 )
/* ----------------------- Static functions ---------------------------------*/
eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
/* ----------------------- Start implementation -----------------------------*/
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
#if MB_FUNC_WRITE_HOLDING_ENABLED > 0
/**
* This function will request write holding register.
*
* @param ucSndAddr salve address
* @param usRegAddr register start address
* @param usRegData register data to be written
* @param lTimeOut timeout (-1 will waiting forever)
*
* @return error code
*/
eMBMasterReqErrCode
eMBMasterReqWriteHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usRegData, LONG lTimeOut )
{
UCHAR *ucMBFrame;
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
else
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
vMBMasterSetDestAddress(ucSndAddr);
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_WRITE_REGISTER;
ucMBFrame[MB_PDU_REQ_WRITE_ADDR_OFF] = usRegAddr >> 8;
ucMBFrame[MB_PDU_REQ_WRITE_ADDR_OFF + 1] = usRegAddr;
ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF] = usRegData >> 8;
ucMBFrame[MB_PDU_REQ_WRITE_VALUE_OFF + 1] = usRegData ;
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_SIZE );
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
eErrStatus = eMBMasterWaitRequestFinish( );
}
return eErrStatus;
}
eMBException
eMBMasterFuncWriteHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
{
USHORT usRegAddress;
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
if( *usLen == ( MB_PDU_SIZE_MIN + MB_PDU_FUNC_WRITE_SIZE ) )
{
usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF] << 8 );
usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF + 1] );
usRegAddress++;
/* Make callback to update the value. */
eRegStatus = eMBMasterRegHoldingCB( &pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF],
usRegAddress, 1, MB_REG_WRITE );
/* If an error occured convert it into a Modbus exception. */
if( eRegStatus != MB_ENOERR )
{
eStatus = prveMBError2Exception( eRegStatus );
}
}
else
{
/* Can't be a valid request because the length is incorrect. */
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
return eStatus;
}
#endif
#if MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED > 0
/**
* This function will request write multiple holding register.
*
* @param ucSndAddr salve address
* @param usRegAddr register start address
* @param usNRegs register total number
* @param pusDataBuffer data to be written
* @param lTimeOut timeout (-1 will waiting forever)
*
* @return error code
*/
eMBMasterReqErrCode
eMBMasterReqWriteMultipleHoldingRegister( UCHAR ucSndAddr,
USHORT usRegAddr, USHORT usNRegs, USHORT * pusDataBuffer, LONG lTimeOut )
{
UCHAR *ucMBFrame;
USHORT usRegIndex = 0;
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
else
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
vMBMasterSetDestAddress(ucSndAddr);
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_WRITE_MULTIPLE_REGISTERS;
ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF] = usRegAddr >> 8;
ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF + 1] = usRegAddr;
ucMBFrame[MB_PDU_REQ_WRITE_MUL_REGCNT_OFF] = usNRegs >> 8;
ucMBFrame[MB_PDU_REQ_WRITE_MUL_REGCNT_OFF + 1] = usNRegs ;
ucMBFrame[MB_PDU_REQ_WRITE_MUL_BYTECNT_OFF] = usNRegs * 2;
ucMBFrame += MB_PDU_REQ_WRITE_MUL_VALUES_OFF;
while( usNRegs > usRegIndex)
{
*ucMBFrame++ = pusDataBuffer[usRegIndex] >> 8;
*ucMBFrame++ = pusDataBuffer[usRegIndex++] ;
}
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_MUL_SIZE_MIN + 2*usNRegs );
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
eErrStatus = eMBMasterWaitRequestFinish( );
}
return eErrStatus;
}
eMBException
eMBMasterFuncWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
{
UCHAR *ucMBFrame;
USHORT usRegAddress;
USHORT usRegCount;
UCHAR ucRegByteCount;
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
/* If this request is broadcast, the *usLen is not need check. */
if( ( *usLen == MB_PDU_SIZE_MIN + MB_PDU_FUNC_WRITE_MUL_SIZE ) || xMBMasterRequestIsBroadcast() )
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
usRegAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF] << 8 );
usRegAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_WRITE_MUL_ADDR_OFF + 1] );
usRegAddress++;
usRegCount = ( USHORT )( ucMBFrame[MB_PDU_REQ_WRITE_MUL_REGCNT_OFF] << 8 );
usRegCount |= ( USHORT )( ucMBFrame[MB_PDU_REQ_WRITE_MUL_REGCNT_OFF + 1] );
ucRegByteCount = ucMBFrame[MB_PDU_REQ_WRITE_MUL_BYTECNT_OFF];
if( ucRegByteCount == 2 * usRegCount )
{
/* Make callback to update the register values. */
eRegStatus =
eMBMasterRegHoldingCB( &ucMBFrame[MB_PDU_REQ_WRITE_MUL_VALUES_OFF],
usRegAddress, usRegCount, MB_REG_WRITE );
/* If an error occured convert it into a Modbus exception. */
if( eRegStatus != MB_ENOERR )
{
eStatus = prveMBError2Exception( eRegStatus );
}
}
else
{
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
}
else
{
/* Can't be a valid request because the length is incorrect. */
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
return eStatus;
}
#endif
#if MB_FUNC_READ_HOLDING_ENABLED > 0
/**
* This function will request read holding register.
*
* @param ucSndAddr salve address
* @param usRegAddr register start address
* @param usNRegs register total number
* @param lTimeOut timeout (-1 will waiting forever)
*
* @return error code
*/
eMBMasterReqErrCode
eMBMasterReqReadHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs, LONG lTimeOut )
{
UCHAR *ucMBFrame;
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
else
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
vMBMasterSetDestAddress(ucSndAddr);
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_READ_HOLDING_REGISTER;
ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] = usRegAddr >> 8;
ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] = usRegAddr;
ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF] = usNRegs >> 8;
ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF + 1] = usNRegs;
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE );
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
eErrStatus = eMBMasterWaitRequestFinish( );
}
return eErrStatus;
}
eMBException
eMBMasterFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
{
UCHAR *ucMBFrame;
USHORT usRegAddress;
USHORT usRegCount;
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
/* If this request is broadcast, and it's read mode. This request don't need execute. */
if ( xMBMasterRequestIsBroadcast() )
{
eStatus = MB_EX_NONE;
}
else if( *usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READ_SIZE_MIN )
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
usRegAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] << 8 );
usRegAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] );
usRegAddress++;
usRegCount = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF] << 8 );
usRegCount |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF + 1] );
/* Check if the number of registers to read is valid. If not
* return Modbus illegal data value exception.
*/
if( ( usRegCount >= 1 ) && ( 2 * usRegCount == pucFrame[MB_PDU_FUNC_READ_BYTECNT_OFF] ) )
{
/* Make callback to fill the buffer. */
eRegStatus = eMBMasterRegHoldingCB( &pucFrame[MB_PDU_FUNC_READ_VALUES_OFF], usRegAddress, usRegCount, MB_REG_READ );
/* If an error occured convert it into a Modbus exception. */
if( eRegStatus != MB_ENOERR )
{
eStatus = prveMBError2Exception( eRegStatus );
}
}
else
{
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
}
else
{
/* Can't be a valid request because the length is incorrect. */
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
return eStatus;
}
#endif
#if MB_FUNC_READWRITE_HOLDING_ENABLED > 0
/**
* This function will request read and write holding register.
*
* @param ucSndAddr salve address
* @param usReadRegAddr read register start address
* @param usNReadRegs read register total number
* @param pusDataBuffer data to be written
* @param usWriteRegAddr write register start address
* @param usNWriteRegs write register total number
* @param lTimeOut timeout (-1 will waiting forever)
*
* @return error code
*/
eMBMasterReqErrCode
eMBMasterReqReadWriteMultipleHoldingRegister( UCHAR ucSndAddr,
USHORT usReadRegAddr, USHORT usNReadRegs, USHORT * pusDataBuffer,
USHORT usWriteRegAddr, USHORT usNWriteRegs, LONG lTimeOut )
{
UCHAR *ucMBFrame;
USHORT usRegIndex = 0;
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
else
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
vMBMasterSetDestAddress(ucSndAddr);
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_READWRITE_MULTIPLE_REGISTERS;
ucMBFrame[MB_PDU_REQ_READWRITE_READ_ADDR_OFF] = usReadRegAddr >> 8;
ucMBFrame[MB_PDU_REQ_READWRITE_READ_ADDR_OFF + 1] = usReadRegAddr;
ucMBFrame[MB_PDU_REQ_READWRITE_READ_REGCNT_OFF] = usNReadRegs >> 8;
ucMBFrame[MB_PDU_REQ_READWRITE_READ_REGCNT_OFF + 1] = usNReadRegs ;
ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF] = usWriteRegAddr >> 8;
ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF + 1] = usWriteRegAddr;
ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF] = usNWriteRegs >> 8;
ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF + 1] = usNWriteRegs ;
ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_BYTECNT_OFF] = usNWriteRegs * 2;
ucMBFrame += MB_PDU_REQ_READWRITE_WRITE_VALUES_OFF;
while( usNWriteRegs > usRegIndex)
{
*ucMBFrame++ = pusDataBuffer[usRegIndex] >> 8;
*ucMBFrame++ = pusDataBuffer[usRegIndex++] ;
}
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READWRITE_SIZE_MIN + 2*usNWriteRegs );
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
eErrStatus = eMBMasterWaitRequestFinish( );
}
return eErrStatus;
}
eMBException
eMBMasterFuncReadWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
{
USHORT usRegReadAddress;
USHORT usRegReadCount;
USHORT usRegWriteAddress;
USHORT usRegWriteCount;
UCHAR *ucMBFrame;
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
/* If this request is broadcast, and it's read mode. This request don't need execute. */
if ( xMBMasterRequestIsBroadcast() )
{
eStatus = MB_EX_NONE;
}
else if( *usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READWRITE_SIZE_MIN )
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
usRegReadAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_READ_ADDR_OFF] << 8U );
usRegReadAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_READ_ADDR_OFF + 1] );
usRegReadAddress++;
usRegReadCount = ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_READ_REGCNT_OFF] << 8U );
usRegReadCount |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_READ_REGCNT_OFF + 1] );
usRegWriteAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF] << 8U );
usRegWriteAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_ADDR_OFF + 1] );
usRegWriteAddress++;
usRegWriteCount = ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF] << 8U );
usRegWriteCount |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_REGCNT_OFF + 1] );
if( ( 2 * usRegReadCount ) == pucFrame[MB_PDU_FUNC_READWRITE_READ_BYTECNT_OFF] )
{
/* Make callback to update the register values. */
eRegStatus = eMBMasterRegHoldingCB( &ucMBFrame[MB_PDU_REQ_READWRITE_WRITE_VALUES_OFF],
usRegWriteAddress, usRegWriteCount, MB_REG_WRITE );
if( eRegStatus == MB_ENOERR )
{
/* Make the read callback. */
eRegStatus = eMBMasterRegHoldingCB(&pucFrame[MB_PDU_FUNC_READWRITE_READ_VALUES_OFF],
usRegReadAddress, usRegReadCount, MB_REG_READ);
}
if( eRegStatus != MB_ENOERR )
{
eStatus = prveMBError2Exception( eRegStatus );
}
}
else
{
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
}
return eStatus;
}
#endif
#endif

View File

@ -1,4 +1,4 @@
/*
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
* All rights reserved.
@ -25,6 +25,7 @@
* (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 ----------------------------------*/
@ -74,7 +75,7 @@ eMBFuncReadInputRegister( UCHAR * pucFrame, USHORT * usLen )
usRegCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );
/* Check if the number of registers to read is valid. If not
* return Modbus illegal data value exception.
* return Modbus illegal data value exception.
*/
if( ( usRegCount >= 1 )
&& ( usRegCount < MB_PDU_FUNC_READ_REGCNT_MAX ) )

View File

@ -0,0 +1,148 @@
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbfuncinput_m.c,v 1.60 2013/10/12 14:23:40 Armink Add Master Functions Exp $
*/
/* ----------------------- System includes ----------------------------------*/
#include "stdlib.h"
#include "string.h"
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mb_m.h"
#include "mbframe.h"
#include "mbproto.h"
#include "mbconfig.h"
/* ----------------------- Defines ------------------------------------------*/
#define MB_PDU_REQ_READ_ADDR_OFF ( MB_PDU_DATA_OFF + 0 )
#define MB_PDU_REQ_READ_REGCNT_OFF ( MB_PDU_DATA_OFF + 2 )
#define MB_PDU_REQ_READ_SIZE ( 4 )
#define MB_PDU_FUNC_READ_BYTECNT_OFF ( MB_PDU_DATA_OFF + 0 )
#define MB_PDU_FUNC_READ_VALUES_OFF ( MB_PDU_DATA_OFF + 1 )
#define MB_PDU_FUNC_READ_SIZE_MIN ( 1 )
#define MB_PDU_FUNC_READ_RSP_BYTECNT_OFF ( MB_PDU_DATA_OFF )
/* ----------------------- Static functions ---------------------------------*/
eMBException prveMBError2Exception( eMBErrorCode eErrorCode );
/* ----------------------- Start implementation -----------------------------*/
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
#if MB_FUNC_READ_INPUT_ENABLED > 0
/**
* This function will request read input register.
*
* @param ucSndAddr salve address
* @param usRegAddr register start address
* @param usNRegs register total number
* @param lTimeOut timeout (-1 will waiting forever)
*
* @return error code
*/
eMBMasterReqErrCode
eMBMasterReqReadInputRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs, LONG lTimeOut )
{
UCHAR *ucMBFrame;
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
if ( ucSndAddr > MB_MASTER_TOTAL_SLAVE_NUM ) eErrStatus = MB_MRE_ILL_ARG;
else if ( xMBMasterRunResTake( lTimeOut ) == FALSE ) eErrStatus = MB_MRE_MASTER_BUSY;
else
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
vMBMasterSetDestAddress(ucSndAddr);
ucMBFrame[MB_PDU_FUNC_OFF] = MB_FUNC_READ_INPUT_REGISTER;
ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] = usRegAddr >> 8;
ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] = usRegAddr;
ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF] = usNRegs >> 8;
ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF + 1] = usNRegs;
vMBMasterSetPDUSndLength( MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE );
( void ) xMBMasterPortEventPost( EV_MASTER_FRAME_SENT );
eErrStatus = eMBMasterWaitRequestFinish( );
}
return eErrStatus;
}
eMBException
eMBMasterFuncReadInputRegister( UCHAR * pucFrame, USHORT * usLen )
{
UCHAR *ucMBFrame;
USHORT usRegAddress;
USHORT usRegCount;
eMBException eStatus = MB_EX_NONE;
eMBErrorCode eRegStatus;
/* If this request is broadcast, and it's read mode. This request don't need execute. */
if ( xMBMasterRequestIsBroadcast() )
{
eStatus = MB_EX_NONE;
}
else if( *usLen >= MB_PDU_SIZE_MIN + MB_PDU_FUNC_READ_SIZE_MIN )
{
vMBMasterGetPDUSndBuf(&ucMBFrame);
usRegAddress = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF] << 8 );
usRegAddress |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_ADDR_OFF + 1] );
usRegAddress++;
usRegCount = ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF] << 8 );
usRegCount |= ( USHORT )( ucMBFrame[MB_PDU_REQ_READ_REGCNT_OFF + 1] );
/* Check if the number of registers to read is valid. If not
* return Modbus illegal data value exception.
*/
if( ( usRegCount >= 1 ) && ( 2 * usRegCount == pucFrame[MB_PDU_FUNC_READ_BYTECNT_OFF] ) )
{
/* Make callback to fill the buffer. */
eRegStatus = eMBMasterRegInputCB( &pucFrame[MB_PDU_FUNC_READ_VALUES_OFF], usRegAddress, usRegCount );
/* If an error occured convert it into a Modbus exception. */
if( eRegStatus != MB_ENOERR )
{
eStatus = prveMBError2Exception( eRegStatus );
}
}
else
{
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
}
else
{
/* Can't be a valid request because the length is incorrect. */
eStatus = MB_EX_ILLEGAL_DATA_VALUE;
}
return eStatus;
}
#endif
#endif

View File

@ -1,4 +1,4 @@
/*
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
* All rights reserved.
@ -25,6 +25,7 @@
* (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 ----------------------------------*/

View File

@ -1,4 +1,4 @@
/*
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
* All rights reserved.
@ -25,6 +25,7 @@
* (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 ----------------------------------*/
@ -52,8 +53,15 @@ xMBUtilSetBits( UCHAR * ucByteBuf, USHORT usBitOffset, UCHAR ucNBits,
USHORT usNPreBits;
USHORT usValue = ucValue;
assert( ucNBits <= 8 );
assert( ( size_t )BITS_UCHAR == sizeof( UCHAR ) * 8 );
#ifdef ADD_RTTHREAD_FEATURES
RT_ASSERT( ucNBits <= 8 );
RT_ASSERT( ( size_t )BITS_UCHAR == sizeof( UCHAR ) * 8 );
#endif
#ifdef ADD_XIZI_FEATURES
MB_CHECK( ucNBits <= 8 );
MB_CHECK( ( size_t )BITS_UCHAR == sizeof( UCHAR ) * 8 );
#endif
/* Calculate byte offset for first byte containing the bit values starting
* at usBitOffset. */

View File

@ -1,4 +1,4 @@
/*
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
* All rights reserved.
@ -25,6 +25,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mb.h,v 1.17 2006/12/07 22:10:34 wolti Exp $
*/
#ifndef _MB_H
@ -70,7 +71,7 @@ PR_BEGIN_EXTERN_C
/*! \ingroup modbus
* \brief Use the default Modbus TCP port (502)
*/
#define MB_TCP_PORT_USE_DEFAULT 0
#define MB_TCP_PORT_USE_DEFAULT 0
/* ----------------------- Type definitions ---------------------------------*/
@ -96,7 +97,7 @@ PR_BEGIN_EXTERN_C
* registers should be updated and reading means that the modbus protocol
* stack needs to know the current register values.
*
* \see eMBRegHoldingCB( ), eMBRegCoilsCB( ), eMBRegDiscreteCB( ) and
* \see eMBRegHoldingCB( ), eMBRegCoilsCB( ), eMBRegDiscreteCB( ) and
* eMBRegInputCB( ).
*/
typedef enum
@ -141,7 +142,7 @@ typedef enum
*
* \return If no error occurs the function returns eMBErrorCode::MB_ENOERR.
* The protocol is then in the disabled state and ready for activation
* by calling eMBEnable( ). Otherwise one of the following error codes
* by calling eMBEnable( ). Otherwise one of the following error codes
* is returned:
* - eMBErrorCode::MB_EINVAL If the slave address was not valid. Valid
* slave addresses are in the range 1 - 247.
@ -170,10 +171,10 @@ eMBErrorCode eMBTCPInit( USHORT usTCPPort );
* \brief Release resources used by the protocol stack.
*
* This function disables the Modbus protocol stack and release all
* hardware resources. It must only be called when the protocol stack
* is disabled.
* hardware resources. It must only be called when the protocol stack
* is disabled.
*
* \note Note all ports implement this function. A port which wants to
* \note Note all ports implement this function. A port which wants to
* get an callback must define the macro MB_PORT_HAS_CLOSE to 1.
*
* \return If the resources where released it return eMBErrorCode::MB_ENOERR.
@ -188,8 +189,8 @@ eMBErrorCode eMBClose( void );
* This function enables processing of Modbus frames. Enabling the protocol
* stack is only possible if it is in the disabled state.
*
* \return If the protocol stack is now in the state enabled it returns
* eMBErrorCode::MB_ENOERR. If it was not in the disabled state it
* \return If the protocol stack is now in the state enabled it returns
* eMBErrorCode::MB_ENOERR. If it was not in the disabled state it
* return eMBErrorCode::MB_EILLSTATE.
*/
eMBErrorCode eMBEnable( void );
@ -199,7 +200,7 @@ eMBErrorCode eMBEnable( void );
*
* This function disables processing of Modbus frames.
*
* \return If the protocol stack has been disabled it returns
* \return If the protocol stack has been disabled it returns
* eMBErrorCode::MB_ENOERR. If it was not in the enabled state it returns
* eMBErrorCode::MB_EILLSTATE.
*/
@ -211,10 +212,10 @@ eMBErrorCode eMBDisable( void );
* This function must be called periodically. The timer interval required
* is given by the application dependent Modbus slave timeout. Internally the
* function calls xMBPortEventGet() and waits for an event from the receiver or
* transmitter state machines.
* transmitter state machines.
*
* \return If the protocol stack is not in the enabled state the function
* returns eMBErrorCode::MB_EILLSTATE. Otherwise it returns
* returns eMBErrorCode::MB_EILLSTATE. Otherwise it returns
* eMBErrorCode::MB_ENOERR.
*/
eMBErrorCode eMBPoll( void );
@ -248,7 +249,7 @@ eMBErrorCode eMBSetSlaveID( UCHAR ucSlaveID, BOOL xIsRunning,
* The callback handler supplied is responsible for interpreting the Modbus PDU and
* the creation of an appropriate response. In case of an error it should return
* one of the possible Modbus exceptions which results in a Modbus exception frame
* sent by the protocol stack.
* sent by the protocol stack.
*
* \param ucFunctionCode The Modbus function code for which this handler should
* be registers. Valid function codes are in the range 1 to 127.
@ -261,7 +262,7 @@ eMBErrorCode eMBSetSlaveID( UCHAR ucSlaveID, BOOL xIsRunning,
* case the values in mbconfig.h should be adjusted. If the argument was not
* valid it returns eMBErrorCode::MB_EINVAL.
*/
eMBErrorCode eMBRegisterCB( UCHAR ucFunctionCode,
eMBErrorCode eMBRegisterCB( UCHAR ucFunctionCode,
pxMBFunctionHandler pxHandler );
/* ----------------------- Callback -----------------------------------------*/
@ -299,7 +300,7 @@ eMBErrorCode eMBRegisterCB( UCHAR ucFunctionCode,
* - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
* Modbus response is sent.
* - eMBErrorCode::MB_ENOREG If the application can not supply values
* for registers within this range. In this case a
* for registers within this range. In this case a
* <b>ILLEGAL DATA ADDRESS</b> exception frame is sent as a response.
* - eMBErrorCode::MB_ETIMEDOUT If the requested register block is
* currently not available and the application dependent response
@ -323,18 +324,18 @@ eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress,
* this buffer.
* \param usAddress The starting address of the register.
* \param usNRegs Number of registers to read or write.
* \param eMode If eMBRegisterMode::MB_REG_WRITE the application register
* \param eMode If eMBRegisterMode::MB_REG_WRITE the application register
* values should be updated from the values in the buffer. For example
* this would be the case when the Modbus master has issued an
* this would be the case when the Modbus master has issued an
* <b>WRITE SINGLE REGISTER</b> command.
* If the value eMBRegisterMode::MB_REG_READ the application should copy
* If the value eMBRegisterMode::MB_REG_READ the application should copy
* the current values into the buffer \c pucRegBuffer.
*
* \return The function must return one of the following error codes:
* - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
* Modbus response is sent.
* - eMBErrorCode::MB_ENOREG If the application can not supply values
* for registers within this range. In this case a
* for registers within this range. In this case a
* <b>ILLEGAL DATA ADDRESS</b> exception frame is sent as a response.
* - eMBErrorCode::MB_ETIMEDOUT If the requested register block is
* currently not available and the application dependent response
@ -369,7 +370,7 @@ eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress,
* - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
* Modbus response is sent.
* - eMBErrorCode::MB_ENOREG If the application does not map an coils
* within the requested address range. In this case a
* within the requested address range. In this case a
* <b>ILLEGAL DATA ADDRESS</b> is sent as a response.
* - eMBErrorCode::MB_ETIMEDOUT If the requested register block is
* currently not available and the application dependent response
@ -398,7 +399,7 @@ eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress,
* - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
* Modbus response is sent.
* - eMBErrorCode::MB_ENOREG If no such discrete inputs exists.
* In this case a <b>ILLEGAL DATA ADDRESS</b> exception frame is sent
* In this case a <b>ILLEGAL DATA ADDRESS</b> exception frame is sent
* as a response.
* - eMBErrorCode::MB_ETIMEDOUT If the requested register block is
* currently not available and the application dependent response

View File

@ -0,0 +1,414 @@
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mb_m.h,v 1.60 2013/09/03 10:20:05 Armink Add Master Functions $
*/
#ifndef _MB_M_H
#define _MB_M_H
#ifdef __cplusplus
PR_BEGIN_EXTERN_C
#endif
/*! \defgroup modbus Modbus
* \code #include "mb_m.h" \endcode
*
* This module defines the interface for the application. It contains
* the basic functions and types required to use the Modbus Master protocol stack.
* A typical application will want to call eMBMasterInit() first. If the device
* is ready to answer network requests it must then call eMBEnable() to activate
* the protocol stack. In the main loop the function eMBMasterPoll() must be called
* periodically. The time interval between pooling depends on the configured
* Modbus timeout. If an RTOS is available a separate task should be created
* and the task should always call the function eMBMasterPoll().
*
* \code
* // Initialize protocol stack in RTU mode for a Master
* eMBMasterInit( MB_RTU, 38400, MB_PAR_EVEN );
* // Enable the Modbus Protocol Stack.
* eMBMasterEnable( );
* for( ;; )
* {
* // Call the main polling loop of the Modbus Master protocol stack.
* eMBMasterPoll( );
* ...
* }
* \endcode
*/
/* ----------------------- Defines ------------------------------------------*/
/*! \ingroup modbus
* \brief Use the default Modbus Master TCP port (502)
*/
#define MB_MASTER_TCP_PORT_USE_DEFAULT 0
/* ----------------------- Type definitions ---------------------------------*/
/*! \ingroup modbus
* \brief Errorcodes used by all function in the Master request.
*/
typedef enum
{
MB_MRE_NO_ERR, /*!< no error. */
MB_MRE_NO_REG, /*!< illegal register address. */
MB_MRE_ILL_ARG, /*!< illegal argument. */
MB_MRE_REV_DATA, /*!< receive data error. */
MB_MRE_TIMEDOUT, /*!< timeout error occurred. */
MB_MRE_MASTER_BUSY, /*!< master is busy now. */
MB_MRE_EXE_FUN /*!< execute function error. */
} eMBMasterReqErrCode;
/*! \ingroup modbus
* \brief TimerMode is Master 3 kind of Timer modes.
*/
typedef enum
{
MB_TMODE_T35, /*!< Master receive frame T3.5 timeout. */
MB_TMODE_RESPOND_TIMEOUT, /*!< Master wait respond for slave. */
MB_TMODE_CONVERT_DELAY /*!< Master sent broadcast ,then delay sometime.*/
}eMBMasterTimerMode;
/* ----------------------- Function prototypes ------------------------------*/
/*! \ingroup modbus
* \brief Initialize the Modbus Master protocol stack.
*
* This functions initializes the ASCII or RTU module and calls the
* init functions of the porting layer to prepare the hardware. Please
* note that the receiver is still disabled and no Modbus frames are
* processed until eMBMasterEnable( ) has been called.
*
* \param eMode If ASCII or RTU mode should be used.
* \param ucPort The port to use. E.g. 1 for COM1 on windows. This value
* is platform dependent and some ports simply choose to ignore it.
* \param ulBaudRate The baudrate. E.g. 19200. Supported baudrates depend
* on the porting layer.
* \param eParity Parity used for serial transmission.
*
* \return If no error occurs the function returns eMBErrorCode::MB_ENOERR.
* The protocol is then in the disabled state and ready for activation
* by calling eMBMasterEnable( ). Otherwise one of the following error codes
* is returned:
* - eMBErrorCode::MB_EPORTERR IF the porting layer returned an error.
*/
eMBErrorCode eMBMasterInit( eMBMode eMode, UCHAR ucPort,
ULONG ulBaudRate, eMBParity eParity );
/*! \ingroup modbus
* \brief Initialize the Modbus Master protocol stack for Modbus TCP.
*
* This function initializes the Modbus TCP Module. Please note that
* frame processing is still disabled until eMBEnable( ) is called.
*
* \param usTCPPort The TCP port to listen on.
* \return If the protocol stack has been initialized correctly the function
* returns eMBErrorCode::MB_ENOERR. Otherwise one of the following error
* codes is returned:
* - eMBErrorCode::MB_EINVAL If the slave address was not valid. Valid
* slave addresses are in the range 1 - 247.
* - eMBErrorCode::MB_EPORTERR IF the porting layer returned an error.
*/
eMBErrorCode eMBMasterTCPInit( USHORT usTCPPort );
/*! \ingroup modbus
* \brief Release resources used by the protocol stack.
*
* This function disables the Modbus Master protocol stack and release all
* hardware resources. It must only be called when the protocol stack
* is disabled.
*
* \note Note all ports implement this function. A port which wants to
* get an callback must define the macro MB_PORT_HAS_CLOSE to 1.
*
* \return If the resources where released it return eMBErrorCode::MB_ENOERR.
* If the protocol stack is not in the disabled state it returns
* eMBErrorCode::MB_EILLSTATE.
*/
eMBErrorCode eMBMasterClose( void );
/*! \ingroup modbus
* \brief Enable the Modbus Master protocol stack.
*
* This function enables processing of Modbus Master frames. Enabling the protocol
* stack is only possible if it is in the disabled state.
*
* \return If the protocol stack is now in the state enabled it returns
* eMBErrorCode::MB_ENOERR. If it was not in the disabled state it
* return eMBErrorCode::MB_EILLSTATE.
*/
eMBErrorCode eMBMasterEnable( void );
/*! \ingroup modbus
* \brief Disable the Modbus Master protocol stack.
*
* This function disables processing of Modbus frames.
*
* \return If the protocol stack has been disabled it returns
* eMBErrorCode::MB_ENOERR. If it was not in the enabled state it returns
* eMBErrorCode::MB_EILLSTATE.
*/
eMBErrorCode eMBMasterDisable( void );
/*! \ingroup modbus
* \brief Check the Modbus Master protocol stack has established or not.
*
* This function must be called and check the return value before calling
* any other functions.
*
* \return If the protocol stack has been established or not
* TRUE. the protocol stack has established
* FALSE. the protocol stack hasn't established
*/
BOOL eMBMasterIsEstablished( void );
/*! \ingroup modbus
* \brief The main pooling loop of the Modbus Master protocol stack.
*
* This function must be called periodically. The timer interval required
* is given by the application dependent Modbus slave timeout. Internally the
* function calls xMBMasterPortEventGet() and waits for an event from the receiver or
* transmitter state machines.
*
* \return If the protocol stack is not in the enabled state the function
* returns eMBErrorCode::MB_EILLSTATE. Otherwise it returns
* eMBErrorCode::MB_ENOERR.
*/
eMBErrorCode eMBMasterPoll( void );
/*! \ingroup modbus
* \brief Registers a callback handler for a given function code.
*
* This function registers a new callback handler for a given function code.
* The callback handler supplied is responsible for interpreting the Modbus PDU and
* the creation of an appropriate response. In case of an error it should return
* one of the possible Modbus exceptions which results in a Modbus exception frame
* sent by the protocol stack.
*
* \param ucFunctionCode The Modbus function code for which this handler should
* be registers. Valid function codes are in the range 1 to 127.
* \param pxHandler The function handler which should be called in case
* such a frame is received. If \c NULL a previously registered function handler
* for this function code is removed.
*
* \return eMBErrorCode::MB_ENOERR if the handler has been installed. If no
* more resources are available it returns eMBErrorCode::MB_ENORES. In this
* case the values in mbconfig.h should be adjusted. If the argument was not
* valid it returns eMBErrorCode::MB_EINVAL.
*/
eMBErrorCode eMBMasterRegisterCB( UCHAR ucFunctionCode,
pxMBFunctionHandler pxHandler );
/* ----------------------- Callback -----------------------------------------*/
/*! \defgroup modbus_master registers Modbus Registers
* \code #include "mb_m.h" \endcode
* The protocol stack does not internally allocate any memory for the
* registers. This makes the protocol stack very small and also usable on
* low end targets. In addition the values don't have to be in the memory
* and could for example be stored in a flash.<br>
* Whenever the protocol stack requires a value it calls one of the callback
* function with the register address and the number of registers to read
* as an argument. The application should then read the actual register values
* (for example the ADC voltage) and should store the result in the supplied
* buffer.<br>
* If the protocol stack wants to update a register value because a write
* register function was received a buffer with the new register values is
* passed to the callback function. The function should then use these values
* to update the application register values.
*/
/*! \ingroup modbus_registers
* \brief Callback function used if the value of a <em>Input Register</em>
* is required by the protocol stack. The starting register address is given
* by \c usAddress and the last register is given by <tt>usAddress +
* usNRegs - 1</tt>.
*
* \param pucRegBuffer A buffer where the callback function should write
* the current value of the modbus registers to.
* \param usAddress The starting address of the register. Input registers
* are in the range 1 - 65535.
* \param usNRegs Number of registers the callback function must supply.
*
* \return The function must return one of the following error codes:
* - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
* Modbus response is sent.
* - eMBErrorCode::MB_ENOREG If the application does not map an coils
* within the requested address range. In this case a
* <b>ILLEGAL DATA ADDRESS</b> is sent as a response.
*/
eMBErrorCode eMBMasterRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress,
USHORT usNRegs );
/*! \ingroup modbus_registers
* \brief Callback function used if a <em>Holding Register</em> value is
* read or written by the protocol stack. The starting register address
* is given by \c usAddress and the last register is given by
* <tt>usAddress + usNRegs - 1</tt>.
*
* \param pucRegBuffer If the application registers values should be updated the
* buffer points to the new registers values. If the protocol stack needs
* to now the current values the callback function should write them into
* this buffer.
* \param usAddress The starting address of the register.
* \param usNRegs Number of registers to read or write.
* \param eMode If eMBRegisterMode::MB_REG_WRITE the application register
* values should be updated from the values in the buffer. For example
* this would be the case when the Modbus master has issued an
* <b>WRITE SINGLE REGISTER</b> command.
* If the value eMBRegisterMode::MB_REG_READ the application should copy
* the current values into the buffer \c pucRegBuffer.
*
* \return The function must return one of the following error codes:
* - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
* Modbus response is sent.
* - eMBErrorCode::MB_ENOREG If the application does not map an coils
* within the requested address range. In this case a
* <b>ILLEGAL DATA ADDRESS</b> is sent as a response.
*/
eMBErrorCode eMBMasterRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress,
USHORT usNRegs, eMBRegisterMode eMode );
/*! \ingroup modbus_registers
* \brief Callback function used if a <em>Coil Register</em> value is
* read or written by the protocol stack. If you are going to use
* this function you might use the functions xMBUtilSetBits( ) and
* xMBUtilGetBits( ) for working with bitfields.
*
* \param pucRegBuffer The bits are packed in bytes where the first coil
* starting at address \c usAddress is stored in the LSB of the
* first byte in the buffer <code>pucRegBuffer</code>.
* If the buffer should be written by the callback function unused
* coil values (I.e. if not a multiple of eight coils is used) should be set
* to zero.
* \param usAddress The first coil number.
* \param usNCoils Number of coil values requested.
* \param eMode If eMBRegisterMode::MB_REG_WRITE the application values should
* be updated from the values supplied in the buffer \c pucRegBuffer.
* If eMBRegisterMode::MB_REG_READ the application should store the current
* values in the buffer \c pucRegBuffer.
*
* \return The function must return one of the following error codes:
* - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
* Modbus response is sent.
* - eMBErrorCode::MB_ENOREG If the application does not map an coils
* within the requested address range. In this case a
* <b>ILLEGAL DATA ADDRESS</b> is sent as a response.
*/
eMBErrorCode eMBMasterRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress,
USHORT usNCoils, eMBRegisterMode eMode );
/*! \ingroup modbus_registers
* \brief Callback function used if a <em>Input Discrete Register</em> value is
* read by the protocol stack.
*
* If you are going to use his function you might use the functions
* xMBUtilSetBits( ) and xMBUtilGetBits( ) for working with bitfields.
*
* \param pucRegBuffer The buffer should be updated with the current
* coil values. The first discrete input starting at \c usAddress must be
* stored at the LSB of the first byte in the buffer. If the requested number
* is not a multiple of eight the remaining bits should be set to zero.
* \param usAddress The starting address of the first discrete input.
* \param usNDiscrete Number of discrete input values.
* \return The function must return one of the following error codes:
* - eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal
* Modbus response is sent.
* - eMBErrorCode::MB_ENOREG If the application does not map an coils
* within the requested address range. In this case a
* <b>ILLEGAL DATA ADDRESS</b> is sent as a response.
*/
eMBErrorCode eMBMasterRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress,
USHORT usNDiscrete );
/*! \ingroup modbus
*\brief These Modbus functions are called for user when Modbus run in Master Mode.
*/
eMBMasterReqErrCode
eMBMasterReqReadInputRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs, LONG lTimeOut );
eMBMasterReqErrCode
eMBMasterReqWriteHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usRegData, LONG lTimeOut );
eMBMasterReqErrCode
eMBMasterReqWriteMultipleHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr,
USHORT usNRegs, USHORT * pusDataBuffer, LONG lTimeOut );
eMBMasterReqErrCode
eMBMasterReqReadHoldingRegister( UCHAR ucSndAddr, USHORT usRegAddr, USHORT usNRegs, LONG lTimeOut );
eMBMasterReqErrCode
eMBMasterReqReadWriteMultipleHoldingRegister( UCHAR ucSndAddr,
USHORT usReadRegAddr, USHORT usNReadRegs, USHORT * pusDataBuffer,
USHORT usWriteRegAddr, USHORT usNWriteRegs, LONG lTimeOut );
eMBMasterReqErrCode
eMBMasterReqReadCoils( UCHAR ucSndAddr, USHORT usCoilAddr, USHORT usNCoils, LONG lTimeOut );
eMBMasterReqErrCode
eMBMasterReqWriteCoil( UCHAR ucSndAddr, USHORT usCoilAddr, USHORT usCoilData, LONG lTimeOut );
eMBMasterReqErrCode
eMBMasterReqWriteMultipleCoils( UCHAR ucSndAddr,
USHORT usCoilAddr, USHORT usNCoils, UCHAR * pucDataBuffer, LONG lTimeOut );
eMBMasterReqErrCode
eMBMasterReqReadDiscreteInputs( UCHAR ucSndAddr, USHORT usDiscreteAddr, USHORT usNDiscreteIn, LONG lTimeOut );
eMBException
eMBMasterFuncReportSlaveID( UCHAR * pucFrame, USHORT * usLen );
eMBException
eMBMasterFuncReadInputRegister( UCHAR * pucFrame, USHORT * usLen );
eMBException
eMBMasterFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen );
eMBException
eMBMasterFuncWriteHoldingRegister( UCHAR * pucFrame, USHORT * usLen );
eMBException
eMBMasterFuncWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen );
eMBException
eMBMasterFuncReadCoils( UCHAR * pucFrame, USHORT * usLen );
eMBException
eMBMasterFuncWriteCoil( UCHAR * pucFrame, USHORT * usLen );
eMBException
eMBMasterFuncWriteMultipleCoils( UCHAR * pucFrame, USHORT * usLen );
eMBException
eMBMasterFuncReadDiscreteInputs( UCHAR * pucFrame, USHORT * usLen );
eMBException
eMBMasterFuncReadWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen );
/*\ingroup modbus
*\brief These functions are interface for Modbus Master
*/
void vMBMasterGetPDUSndBuf( UCHAR ** pucFrame );
UCHAR ucMBMasterGetDestAddress( void );
void vMBMasterSetDestAddress( UCHAR Address );
BOOL xMBMasterGetCBRunInMasterMode( void );
void vMBMasterSetCBRunInMasterMode( BOOL IsMasterMode );
USHORT usMBMasterGetPDUSndLength( void );
void vMBMasterSetPDUSndLength( USHORT SendPDULength );
void vMBMasterSetCurTimerMode( eMBMasterTimerMode eMBTimerMode );
BOOL xMBMasterRequestIsBroadcast( void );
eMBMasterErrorEventType eMBMasterGetErrorType( void );
void vMBMasterSetErrorType( eMBMasterErrorEventType errorType );
eMBMasterReqErrCode eMBMasterWaitRequestFinish( void );
/* ----------------------- Callback -----------------------------------------*/
#ifdef __cplusplus
PR_END_EXTERN_C
#endif
#endif

View File

@ -1,4 +1,4 @@
/*
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
* All rights reserved.
@ -25,6 +25,8 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbconfig.h,v 1.14 2006/12/07 22:10:34 wolti Exp $
* $Id: mbconfig.h,v 1.60 2013/08/13 21:19:55 Armink Add Master Functions $
*/
#ifndef _MB_CONFIG_H
@ -42,17 +44,67 @@ PR_BEGIN_EXTERN_C
*
* All of these settings are available in the file <code>mbconfig.h</code>
*/
#include <transform.h>
#ifdef ADD_RTTHREAD_FEATURES
#include <rtconfig.h>
#endif
/*! \addtogroup modbus_cfg
* @{
*/
/*! \brief If Modbus ASCII support is enabled. */
#define MB_ASCII_ENABLED ( 0 )//gai
/*! \brief If Modbus Master ASCII support is enabled. */
#define MB_MASTER_ASCII_ENABLED ( 0 )
/*! \brief If Modbus Master RTU support is enabled. */
#define MB_MASTER_RTU_ENABLED ( 1 )
/*! \brief If Modbus Master TCP support is enabled. */
#define MB_MASTER_TCP_ENABLED ( 0 )
/*! \brief If Modbus RTU support is enabled. */
#define MB_RTU_ENABLED ( 1 )
#ifdef ADD_RTTHREAD_FEATURES
/*! \brief If Modbus Slave ASCII support is enabled. */
#ifdef PKG_MODBUS_SLAVE_ASCII
#define MB_SLAVE_ASCII_ENABLED ( 1 )
#else
#define MB_SLAVE_ASCII_ENABLED ( 0 )
#endif
/*! \brief If Modbus TCP support is enabled. */
#define MB_TCP_ENABLED ( 0 )
/*! \brief If Modbus Slave RTU support is enabled. */
#ifdef PKG_MODBUS_SLAVE_RTU
#define MB_SLAVE_RTU_ENABLED ( 1 )
#else
#define MB_SLAVE_RTU_ENABLED ( 0 )
#endif
/*! \brief If Modbus Slave TCP support is enabled. */
#ifdef PKG_MODBUS_SLAVE_TCP
#define MB_SLAVE_TCP_ENABLED ( 1 )
#else
#define MB_SLAVE_TCP_ENABLED ( 0 )
#endif
#endif
#ifdef ADD_XIZI_FEATURES
/*! \brief If Modbus Slave ASCII support is enabled. */
#ifdef CONNECTION_MODBUS_USING_ASCII_SLAVE
#define MB_SLAVE_ASCII_ENABLED ( 1 )
#else
#define MB_SLAVE_ASCII_ENABLED ( 0 )
#endif
/*! \brief If Modbus Slave RTU support is enabled. */
#ifdef CONNECTION_MODBUS_USING_RTU_SLAVE
#define MB_SLAVE_RTU_ENABLED ( 1 )
#else
#define MB_SLAVE_RTU_ENABLED ( 0 )
#endif
/*! \brief If Modbus Slave TCP support is enabled. */
#ifdef CONNECTION_MODBUS_USING_TCP_SLAVE
#define MB_SLAVE_TCP_ENABLED ( 1 )
#else
#define MB_SLAVE_TCP_ENABLED ( 0 )
#endif
#endif
/*! \brief The character timeout value for Modbus ASCII.
*
@ -61,20 +113,6 @@ PR_BEGIN_EXTERN_C
* time of the network.
*/
#define MB_ASCII_TIMEOUT_SEC ( 1 )
/*! \brief 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.
*/
#ifndef MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS
#define MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS ( 0 )
#endif
/*! \brief Maximum number of Modbus functions codes the protocol stack
* should support.
*
@ -83,7 +121,6 @@ PR_BEGIN_EXTERN_C
* handlers. If set to small adding more functions will fail.
*/
#define MB_FUNC_HANDLERS_MAX ( 16 )
/*! \brief Number of bytes which should be allocated for the <em>Report Slave ID
* </em>command.
*
@ -93,39 +130,42 @@ PR_BEGIN_EXTERN_C
* is set to <code>1</code>.
*/
#define MB_FUNC_OTHER_REP_SLAVEID_BUF ( 32 )
/*! \brief If the <em>Report Slave ID</em> function should be enabled. */
#define MB_FUNC_OTHER_REP_SLAVEID_ENABLED ( 1 )
/*! \brief If the <em>Read Input Registers</em> function should be enabled. */
#define MB_FUNC_READ_INPUT_ENABLED ( 1 )
/*! \brief If the <em>Read Holding Registers</em> function should be enabled. */
#define MB_FUNC_READ_HOLDING_ENABLED ( 1 )
/*! \brief If the <em>Write Single Register</em> function should be enabled. */
#define MB_FUNC_WRITE_HOLDING_ENABLED ( 1 )
/*! \brief If the <em>Write Multiple registers</em> function should be enabled. */
#define MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED ( 1 )
/*! \brief If the <em>Read Coils</em> function should be enabled. */
#define MB_FUNC_READ_COILS_ENABLED ( 1 )
/*! \brief If the <em>Write Coils</em> function should be enabled. */
#define MB_FUNC_WRITE_COIL_ENABLED ( 1 )
/*! \brief If the <em>Write Multiple Coils</em> function should be enabled. */
#define MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED ( 1 )
/*! \brief If the <em>Read Discrete Inputs</em> function should be enabled. */
#define MB_FUNC_READ_DISCRETE_INPUTS_ENABLED ( 1 )
/*! \brief If the <em>Read/Write Multiple Registers</em> function should be enabled. */
#define MB_FUNC_READWRITE_HOLDING_ENABLED ( 1 )
/*! @} */
#ifdef __cplusplus
PR_END_EXTERN_C
#endif
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
/*! \brief If master send a broadcast frame,the master will wait time of convert to delay,
* then master can send other frame */
#define MB_MASTER_DELAY_MS_CONVERT (200 )
/*! \brief If master send a frame which is not broadcast,the master will wait sometime for slave.
* And if slave is not respond in this time,the master will process this timeout error.
* Then master can send other frame */
#define MB_MASTER_TIMEOUT_MS_RESPOND (100 )
/*! \brief The total slaves in Modbus Master system. Default 16.
* \note : The slave ID must be continuous from 1.*/
#define MB_MASTER_TOTAL_SLAVE_NUM ( 16 )
#endif
#endif

View File

@ -1,4 +1,4 @@
/*
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
* All rights reserved.
@ -25,6 +25,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbframe.h,v 1.9 2006/12/07 22:10:34 wolti Exp $
*/
#ifndef _MB_FRAME_H

View File

@ -1,4 +1,4 @@
/*
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
* All rights reserved.
@ -25,8 +25,9 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbfunc.h,v 1.12 2006/12/07 22:10:34 wolti Exp $
*/
#ifndef _MB_FUNC_H
#define _MB_FUNC_H
@ -34,7 +35,7 @@
PR_BEGIN_EXTERN_C
#endif
#if MB_FUNC_OTHER_REP_SLAVEID_BUF > 0
eMBException eMBFuncReportSlaveID( UCHAR * pucFrame, USHORT * usLen );
eMBException eMBFuncReportSlaveID( UCHAR * pucFrame, USHORT * usLen );
#endif
#if MB_FUNC_READ_INPUT_ENABLED > 0

View File

@ -1,4 +1,4 @@
/*
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
* All rights reserved.
@ -25,6 +25,8 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbport.h,v 1.17 2006/12/07 22:10:34 wolti Exp $
* mbport.h,v 1.60 2013/08/17 11:42:56 Armink Add Master Functions $
*/
#ifndef _MB_PORT_H
@ -34,16 +36,38 @@
PR_BEGIN_EXTERN_C
#endif
/* ----------------------- Defines ------------------------------------------*/
/* ----------------------- Type definitions ---------------------------------*/
typedef enum
{
EV_READY, /*!< Startup finished. */
EV_FRAME_RECEIVED, /*!< Frame received. */
EV_EXECUTE, /*!< Execute function. */
EV_FRAME_SENT /*!< Frame sent. */
EV_READY = 1<<0, /*!< Startup finished. */
EV_FRAME_RECEIVED = 1<<1, /*!< Frame received. */
EV_EXECUTE = 1<<2, /*!< Execute function. */
EV_FRAME_SENT = 1<<3 /*!< Frame sent. */
} eMBEventType;
typedef enum
{
EV_MASTER_READY = 1<<0, /*!< Startup finished. */
EV_MASTER_FRAME_RECEIVED = 1<<1, /*!< Frame received. */
EV_MASTER_EXECUTE = 1<<2, /*!< Execute function. */
EV_MASTER_FRAME_SENT = 1<<3, /*!< Frame sent. */
EV_MASTER_ERROR_PROCESS = 1<<4, /*!< Frame error process. */
EV_MASTER_PROCESS_SUCESS = 1<<5, /*!< Request process success. */
EV_MASTER_ERROR_RESPOND_TIMEOUT = 1<<6, /*!< Request respond timeout. */
EV_MASTER_ERROR_RECEIVE_DATA = 1<<7, /*!< Request receive data error. */
EV_MASTER_ERROR_EXECUTE_FUNCTION = 1<<8, /*!< Request execute function error. */
} eMBMasterEventType;
typedef enum
{
EV_ERROR_RESPOND_TIMEOUT, /*!< Slave respond timeout. */
EV_ERROR_RECEIVE_DATA, /*!< Receive frame data erroe. */
EV_ERROR_EXECUTE_FUNCTION, /*!< Execute function error. */
} eMBMasterErrorEventType;
/*! \ingroup modbus
* \brief Parity used for characters in serial mode.
*
@ -65,6 +89,18 @@ BOOL xMBPortEventPost( eMBEventType eEvent );
BOOL xMBPortEventGet( /*@out@ */ eMBEventType * eEvent );
BOOL xMBMasterPortEventInit( void );
BOOL xMBMasterPortEventPost( eMBMasterEventType eEvent );
BOOL xMBMasterPortEventGet( /*@out@ */ eMBMasterEventType * eEvent );
void vMBMasterOsResInit( void );
BOOL xMBMasterRunResTake( int32_t time );
void vMBMasterRunResRelease( void );
/* ----------------------- Serial port functions ----------------------------*/
BOOL xMBPortSerialInit( UCHAR ucPort, ULONG ulBaudRate,
@ -76,20 +112,55 @@ void xMBPortSerialClose( void );
void vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable );
BOOL xMBPortSerialGetByte( CHAR * pucByte );
INLINE BOOL xMBPortSerialGetByte( CHAR * pucByte );
BOOL xMBPortSerialPutByte( CHAR ucByte );
INLINE BOOL xMBPortSerialPutByte( CHAR ucByte );
BOOL xMBMasterPortSerialInit( UCHAR ucPort, ULONG ulBaudRate,
UCHAR ucDataBits, eMBParity eParity );
void vMBMasterPortClose( void );
void xMBMasterPortSerialClose( void );
void vMBMasterPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable );
INLINE BOOL xMBMasterPortSerialGetByte( CHAR * pucByte );
INLINE BOOL xMBMasterPortSerialPutByte( CHAR ucByte );
/* ----------------------- Timers functions ---------------------------------*/
BOOL xMBPortTimersInit( USHORT usTimeOut50us );
void xMBPortTimersClose( void );
void vMBPortTimersEnable( void );
INLINE void vMBPortTimersEnable( void );
void vMBPortTimersDisable( void );
INLINE void vMBPortTimersDisable( void );
void vMBPortTimersDelay( USHORT usTimeOutMS );
BOOL xMBMasterPortTimersInit( USHORT usTimeOut50us );
void xMBMasterPortTimersClose( void );
INLINE void vMBMasterPortTimersT35Enable( void );
INLINE void vMBMasterPortTimersConvertDelayEnable( void );
INLINE void vMBMasterPortTimersRespondTimeoutEnable( void );
INLINE void vMBMasterPortTimersDisable( void );
/* ----------------- Callback for the master error process ------------------*/
void vMBMasterErrorCBRespondTimeout( UCHAR ucDestAddress, const UCHAR* pucPDUData,
USHORT ucPDULength );
void vMBMasterErrorCBReceiveData( UCHAR ucDestAddress, const UCHAR* pucPDUData,
USHORT ucPDULength );
void vMBMasterErrorCBExecuteFunction( UCHAR ucDestAddress, const UCHAR* pucPDUData,
USHORT ucPDULength );
void vMBMasterCBRequestScuuess( void );
/* ----------------------- Callback for the protocol stack ------------------*/
@ -105,12 +176,24 @@ void vMBPortTimersDelay( USHORT usTimeOutMS );
* a new byte was received. The port implementation should wake up the
* tasks which are currently blocked on the eventqueue.
*/
extern BOOL( *pxMBFrameCBByteReceived ) ( void );
extern BOOL( *pxMBFrameCBTransmitterEmpty ) ( void );
extern BOOL( *pxMBPortCBTimerExpired ) ( void );
#ifdef ADD_RTTHREAD_FEATURES
extern BOOL( *pxMBFrameCBByteReceived ) ( void );
extern BOOL( *pxMBMasterFrameCBByteReceived ) ( void );
#endif
#ifdef ADD_XIZI_FEATURES
extern BOOL( *pxMBFrameCBByteReceived ) ( CHAR pucByte );
extern BOOL( *pxMBMasterFrameCBByteReceived ) ( CHAR pucByte );
#endif
extern BOOL( *pxMBMasterFrameCBTransmitterEmpty ) ( void );
extern BOOL( *pxMBMasterPortCBTimerExpired ) ( void );
/* ----------------------- TCP port functions -------------------------------*/
BOOL xMBTCPPortInit( USHORT usTCPPort );

View File

@ -1,4 +1,4 @@
/*
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
* All rights reserved.
@ -25,6 +25,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbproto.h,v 1.14 2006/12/07 22:10:34 wolti Exp $
*/
#ifndef _MB_PROTO_H

View File

@ -1,4 +1,4 @@
/*
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
* All rights reserved.
@ -25,6 +25,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbutils.h,v 1.5 2006/12/07 22:10:34 wolti Exp $
*/
#ifndef _MB_UTILS_H

View File

@ -1,4 +1,4 @@
/*
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
* All rights reserved.
@ -25,6 +25,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mb.c,v 1.27 2007/02/18 23:45:41 wolti Exp $
*/
/* ----------------------- System includes ----------------------------------*/
@ -35,6 +36,7 @@
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbconfig.h"
#include "mbframe.h"
@ -42,13 +44,13 @@
#include "mbfunc.h"
#include "mbport.h"
#if MB_RTU_ENABLED == 1
#if MB_SLAVE_RTU_ENABLED == 1
#include "mbrtu.h"
#endif
#if MB_ASCII_ENABLED == 1
#if MB_SLAVE_ASCII_ENABLED == 1
#include "mbascii.h"
#endif
#if MB_TCP_ENABLED == 1
#if MB_SLAVE_TCP_ENABLED == 1
#include "mbtcp.h"
#endif
@ -70,6 +72,7 @@ static enum
/* Functions pointer which are initialized in eMBInit( ). Depending on the
* mode (RTU or ASCII) the are set to the correct implementations.
* Using for Modbus Slave
*/
static peMBFrameSend peMBFrameSendCur;
static pvMBFrameStart pvMBFrameStartCur;
@ -80,8 +83,14 @@ static pvMBFrameClose pvMBFrameCloseCur;
/* Callback functions required by the porting layer. They are called when
* an external event has happend which includes a timeout or the reception
* or transmission of a character.
* Using for Modbus Slave
*/
#ifdef ADD_RTTHREAD_FEATURES
BOOL( *pxMBFrameCBByteReceived ) ( void );
#endif
#ifdef ADD_XIZI_FEATURES
BOOL( *pxMBFrameCBByteReceived ) ( CHAR pucByte );
#endif
BOOL( *pxMBFrameCBTransmitterEmpty ) ( void );
BOOL( *pxMBPortCBTimerExpired ) ( void );
@ -142,9 +151,9 @@ eMBInit( eMBMode eMode, UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eM
switch ( eMode )
{
#if MB_RTU_ENABLED > 0
#if MB_SLAVE_RTU_ENABLED > 0
case MB_RTU:
pvMBFrameStartCur = eMBRTUStart;//回调
pvMBFrameStartCur = eMBRTUStart;
pvMBFrameStopCur = eMBRTUStop;
peMBFrameSendCur = eMBRTUSend;
peMBFrameReceiveCur = eMBRTUReceive;
@ -156,7 +165,7 @@ eMBInit( eMBMode eMode, UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eM
eStatus = eMBRTUInit( ucMBAddress, ucPort, ulBaudRate, eParity );
break;
#endif
#if MB_ASCII_ENABLED > 0
#if MB_SLAVE_ASCII_ENABLED > 0
case MB_ASCII:
pvMBFrameStartCur = eMBASCIIStart;
pvMBFrameStopCur = eMBASCIIStop;
@ -172,6 +181,7 @@ eMBInit( eMBMode eMode, UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eM
#endif
default:
eStatus = MB_EINVAL;
break;
}
if( eStatus == MB_ENOERR )
@ -191,7 +201,7 @@ eMBInit( eMBMode eMode, UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eM
return eStatus;
}
#if MB_TCP_ENABLED > 0
#if MB_SLAVE_TCP_ENABLED > 0
eMBErrorCode
eMBTCPInit( USHORT ucTCPPort )
{
@ -287,15 +297,16 @@ eMBClose( void )
return eStatus;
}
eMBErrorCode
eMBEnable( void )
{
eMBErrorCode eStatus = MB_ENOERR;
if( eMBState == STATE_DISABLED )//init完成
if( eMBState == STATE_DISABLED )
{
/* Activate the protocol stack. */
pvMBFrameStartCur( );//函数指针在init中指向了eMBRTUStart
pvMBFrameStartCur( );
eMBState = STATE_ENABLED;
}
else
@ -327,8 +338,7 @@ eMBDisable( void )
return eStatus;
}
eMBErrorCode
eMBPoll( void )
eMBErrorCode eMBPoll( void )
{
static UCHAR *ucMBFrame;
static UCHAR ucRcvAddress;
@ -395,10 +405,6 @@ eMBPoll( void )
ucMBFrame[usLength++] = ( UCHAR )( ucFunctionCode | MB_FUNC_ERROR );
ucMBFrame[usLength++] = eException;
}
if( ( eMBCurrentMode == MB_ASCII ) && MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS )
{
vMBPortTimersDelay( MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS );
}
eStatus = peMBFrameSendCur( ucMBAddress, ucMBFrame, usLength );
}
break;

View File

@ -0,0 +1,431 @@
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbrtu_m.c,v 1.60 2013/08/20 11:18:10 Armink Add Master Functions $
*/
/* ----------------------- System includes ----------------------------------*/
#include "stdlib.h"
#include "string.h"
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mb_m.h"
#include "mbconfig.h"
#include "mbframe.h"
#include "mbproto.h"
#include "mbfunc.h"
#include "mbport.h"
#if MB_MASTER_RTU_ENABLED == 1
#include "mbrtu.h"
#endif
#if MB_MASTER_ASCII_ENABLED == 1
#include "mbascii.h"
#endif
#if MB_MASTER_TCP_ENABLED == 1
#include "mbtcp.h"
#endif
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
#ifndef MB_PORT_HAS_CLOSE
#define MB_PORT_HAS_CLOSE 0
#endif
/* ----------------------- Static variables ---------------------------------*/
static UCHAR ucMBMasterDestAddress;
static BOOL xMBRunInMasterMode = FALSE;
static eMBMasterErrorEventType eMBMasterCurErrorType;
static enum
{
STATE_ENABLED,
STATE_DISABLED,
STATE_NOT_INITIALIZED,
STATE_ESTABLISHED,
} eMBState = STATE_NOT_INITIALIZED;
/* Functions pointer which are initialized in eMBInit( ). Depending on the
* mode (RTU or ASCII) the are set to the correct implementations.
* Using for Modbus Master,Add by Armink 20130813
*/
static peMBFrameSend peMBMasterFrameSendCur;
static pvMBFrameStart pvMBMasterFrameStartCur;
static pvMBFrameStop pvMBMasterFrameStopCur;
static peMBFrameReceive peMBMasterFrameReceiveCur;
static pvMBFrameClose pvMBMasterFrameCloseCur;
/* Callback functions required by the porting layer. They are called when
* an external event has happend which includes a timeout or the reception
* or transmission of a character.
* Using for Modbus Master,Add by Armink 20130813
*/
#ifdef ADD_RTTHREAD_FEATURES
BOOL( *pxMBMasterFrameCBByteReceived ) ( void );
#endif
#ifdef ADD_XIZI_FEATURES
BOOL( *pxMBMasterFrameCBByteReceived ) ( CHAR pucByte );
#endif
BOOL( *pxMBMasterFrameCBTransmitterEmpty ) ( void );
BOOL( *pxMBMasterPortCBTimerExpired ) ( void );
BOOL( *pxMBMasterFrameCBReceiveFSMCur ) ( void );
BOOL( *pxMBMasterFrameCBTransmitFSMCur ) ( void );
/* An array of Modbus functions handlers which associates Modbus function
* codes with implementing functions.
*/
static xMBFunctionHandler xMasterFuncHandlers[MB_FUNC_HANDLERS_MAX] = {
#if MB_FUNC_OTHER_REP_SLAVEID_ENABLED > 0
//TODO Add Master function define
{MB_FUNC_OTHER_REPORT_SLAVEID, eMBFuncReportSlaveID},
#endif
#if MB_FUNC_READ_INPUT_ENABLED > 0
{MB_FUNC_READ_INPUT_REGISTER, eMBMasterFuncReadInputRegister},
#endif
#if MB_FUNC_READ_HOLDING_ENABLED > 0
{MB_FUNC_READ_HOLDING_REGISTER, eMBMasterFuncReadHoldingRegister},
#endif
#if MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED > 0
{MB_FUNC_WRITE_MULTIPLE_REGISTERS, eMBMasterFuncWriteMultipleHoldingRegister},
#endif
#if MB_FUNC_WRITE_HOLDING_ENABLED > 0
{MB_FUNC_WRITE_REGISTER, eMBMasterFuncWriteHoldingRegister},
#endif
#if MB_FUNC_READWRITE_HOLDING_ENABLED > 0
{MB_FUNC_READWRITE_MULTIPLE_REGISTERS, eMBMasterFuncReadWriteMultipleHoldingRegister},
#endif
#if MB_FUNC_READ_COILS_ENABLED > 0
{MB_FUNC_READ_COILS, eMBMasterFuncReadCoils},
#endif
#if MB_FUNC_WRITE_COIL_ENABLED > 0
{MB_FUNC_WRITE_SINGLE_COIL, eMBMasterFuncWriteCoil},
#endif
#if MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED > 0
{MB_FUNC_WRITE_MULTIPLE_COILS, eMBMasterFuncWriteMultipleCoils},
#endif
#if MB_FUNC_READ_DISCRETE_INPUTS_ENABLED > 0
{MB_FUNC_READ_DISCRETE_INPUTS, eMBMasterFuncReadDiscreteInputs},
#endif
};
/* ----------------------- Start implementation -----------------------------*/
eMBErrorCode
eMBMasterInit( eMBMode eMode, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity )
{
eMBErrorCode eStatus = MB_ENOERR;
switch (eMode)
{
#if MB_MASTER_RTU_ENABLED > 0
case MB_RTU:
pvMBMasterFrameStartCur = eMBMasterRTUStart;
pvMBMasterFrameStopCur = eMBMasterRTUStop;
peMBMasterFrameSendCur = eMBMasterRTUSend;
peMBMasterFrameReceiveCur = eMBMasterRTUReceive;
pvMBMasterFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBMasterPortClose : NULL;
pxMBMasterFrameCBByteReceived = xMBMasterRTUReceiveFSM;
pxMBMasterFrameCBTransmitterEmpty = xMBMasterRTUTransmitFSM;
pxMBMasterPortCBTimerExpired = xMBMasterRTUTimerExpired;
eStatus = eMBMasterRTUInit(ucPort, ulBaudRate, eParity);
break;
#endif
#if MB_MASTER_ASCII_ENABLED > 0
case MB_ASCII:
pvMBMasterFrameStartCur = eMBMasterASCIIStart;
pvMBMasterFrameStopCur = eMBMasterASCIIStop;
peMBMasterFrameSendCur = eMBMasterASCIISend;
peMBMasterFrameReceiveCur = eMBMasterASCIIReceive;
pvMBMasterFrameCloseCur = MB_PORT_HAS_CLOSE ? vMBMasterPortClose : NULL;
pxMBMasterFrameCBByteReceived = xMBMasterASCIIReceiveFSM;
pxMBMasterFrameCBTransmitterEmpty = xMBMasterASCIITransmitFSM;
pxMBMasterPortCBTimerExpired = xMBMasterASCIITimerT1SExpired;
eStatus = eMBMasterASCIIInit(ucPort, ulBaudRate, eParity );
break;
#endif
default:
eStatus = MB_EINVAL;
break;
}
if (eStatus == MB_ENOERR)
{
if (!xMBMasterPortEventInit())
{
/* port dependent event module initalization failed. */
eStatus = MB_EPORTERR;
}
else
{
eMBState = STATE_DISABLED;
}
/* initialize the OS resource for modbus master. */
vMBMasterOsResInit();
}
return eStatus;
}
eMBErrorCode
eMBMasterClose( void )
{
eMBErrorCode eStatus = MB_ENOERR;
if( eMBState == STATE_DISABLED )
{
if( pvMBMasterFrameCloseCur != NULL )
{
pvMBMasterFrameCloseCur( );
}
}
else
{
eStatus = MB_EILLSTATE;
}
return eStatus;
}
eMBErrorCode
eMBMasterEnable( void )
{
eMBErrorCode eStatus = MB_ENOERR;
if( eMBState == STATE_DISABLED )
{
/* Activate the protocol stack. */
pvMBMasterFrameStartCur( );
eMBState = STATE_ENABLED;
}
else
{
eStatus = MB_EILLSTATE;
}
return eStatus;
}
eMBErrorCode
eMBMasterDisable( void )
{
eMBErrorCode eStatus;
if(( eMBState == STATE_ENABLED ) || ( eMBState == STATE_ESTABLISHED))
{
pvMBMasterFrameStopCur( );
eMBState = STATE_DISABLED;
eStatus = MB_ENOERR;
}
else if( eMBState == STATE_DISABLED )
{
eStatus = MB_ENOERR;
}
else
{
eStatus = MB_EILLSTATE;
}
return eStatus;
}
BOOL
eMBMasterIsEstablished( void )
{
if(eMBState == STATE_ESTABLISHED)
{
return TRUE;
}
else
{
return FALSE;
}
}
eMBErrorCode
eMBMasterPoll( void )
{
static UCHAR *ucMBFrame;
static UCHAR ucRcvAddress;
static UCHAR ucFunctionCode;
static USHORT usLength;
static eMBException eException;
int i , j;
eMBErrorCode eStatus = MB_ENOERR;
eMBMasterEventType eEvent;
eMBMasterErrorEventType errorType;
/* Check if the protocol stack is ready. */
if(( eMBState != STATE_ENABLED ) && ( eMBState != STATE_ESTABLISHED))
{
return MB_EILLSTATE;
}
/* Check if there is a event available. If not return control to caller.
* Otherwise we will handle the event. */
if( xMBMasterPortEventGet( &eEvent ) == TRUE )
{
switch ( eEvent )
{
case EV_MASTER_READY:
eMBState = STATE_ESTABLISHED;
break;
case EV_MASTER_FRAME_RECEIVED:
eStatus = peMBMasterFrameReceiveCur( &ucRcvAddress, &ucMBFrame, &usLength );
/* Check if the frame is for us. If not ,send an error process event. */
if ( ( eStatus == MB_ENOERR ) && ( ucRcvAddress == ucMBMasterGetDestAddress() ) )
{
( void ) xMBMasterPortEventPost( EV_MASTER_EXECUTE );
}
else
{
vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA);
( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
}
break;
case EV_MASTER_EXECUTE:
ucFunctionCode = ucMBFrame[MB_PDU_FUNC_OFF];
eException = MB_EX_ILLEGAL_FUNCTION;
/* If receive frame has exception .The receive function code highest bit is 1.*/
if(ucFunctionCode >> 7) {
eException = (eMBException)ucMBFrame[MB_PDU_DATA_OFF];
}
else
{
for (i = 0; i < MB_FUNC_HANDLERS_MAX; i++)
{
/* No more function handlers registered. Abort. */
if (xMasterFuncHandlers[i].ucFunctionCode == 0) {
break;
}
else if (xMasterFuncHandlers[i].ucFunctionCode == ucFunctionCode) {
vMBMasterSetCBRunInMasterMode(TRUE);
/* If master request is broadcast,
* the master need execute function for all slave.
*/
if ( xMBMasterRequestIsBroadcast() ) {
usLength = usMBMasterGetPDUSndLength();
for(j = 1; j <= MB_MASTER_TOTAL_SLAVE_NUM; j++){
vMBMasterSetDestAddress(j);
eException = xMasterFuncHandlers[i].pxHandler(ucMBFrame, &usLength);
}
}
else {
eException = xMasterFuncHandlers[i].pxHandler(ucMBFrame, &usLength);
}
vMBMasterSetCBRunInMasterMode(FALSE);
break;
}
}
}
/* If master has exception ,Master will send error process.Otherwise the Master is idle.*/
if (eException != MB_EX_NONE) {
vMBMasterSetErrorType(EV_ERROR_EXECUTE_FUNCTION);
( void ) xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
}
else {
vMBMasterCBRequestScuuess( );
vMBMasterRunResRelease( );
}
break;
case EV_MASTER_FRAME_SENT:
/* Master is busy now. */
vMBMasterGetPDUSndBuf( &ucMBFrame );
eStatus = peMBMasterFrameSendCur( ucMBMasterGetDestAddress(), ucMBFrame, usMBMasterGetPDUSndLength() );
break;
case EV_MASTER_ERROR_PROCESS:
/* Execute specified error process callback function. */
errorType = eMBMasterGetErrorType();
vMBMasterGetPDUSndBuf( &ucMBFrame );
switch (errorType) {
case EV_ERROR_RESPOND_TIMEOUT:
vMBMasterErrorCBRespondTimeout(ucMBMasterGetDestAddress(),
ucMBFrame, usMBMasterGetPDUSndLength());
break;
case EV_ERROR_RECEIVE_DATA:
vMBMasterErrorCBReceiveData(ucMBMasterGetDestAddress(),
ucMBFrame, usMBMasterGetPDUSndLength());
break;
case EV_ERROR_EXECUTE_FUNCTION:
vMBMasterErrorCBExecuteFunction(ucMBMasterGetDestAddress(),
ucMBFrame, usMBMasterGetPDUSndLength());
break;
}
vMBMasterRunResRelease();
break;
default:
break;
}
}
return MB_ENOERR;
}
/* Get whether the Modbus Master is run in master mode.*/
BOOL xMBMasterGetCBRunInMasterMode( void )
{
return xMBRunInMasterMode;
}
/* Set whether the Modbus Master is run in master mode.*/
void vMBMasterSetCBRunInMasterMode( BOOL IsMasterMode )
{
xMBRunInMasterMode = IsMasterMode;
}
/* Get Modbus Master send destination address. */
UCHAR ucMBMasterGetDestAddress( void )
{
return ucMBMasterDestAddress;
}
/* Set Modbus Master send destination address. */
void vMBMasterSetDestAddress( UCHAR Address )
{
ucMBMasterDestAddress = Address;
}
/* Get Modbus Master current error event type. */
eMBMasterErrorEventType eMBMasterGetErrorType( void )
{
return eMBMasterCurErrorType;
}
/* Set Modbus Master current error event type. */
void vMBMasterSetErrorType( eMBMasterErrorEventType errorType )
{
eMBMasterCurErrorType = errorType;
}
#endif

View File

@ -0,0 +1,11 @@
SRC_FILES := mbcrc.c
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_RTU_MASTER),y)
SRC_FILES += mbrtu_m.c
endif
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_RTU_SLAVE),y)
SRC_FILES += mbrtu.c
endif
include $(KERNEL_ROOT)/compiler.mk

View File

@ -1,4 +1,4 @@
/*
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
* All rights reserved.
@ -25,6 +25,7 @@
* (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 --------------------------------*/
@ -42,12 +43,12 @@ static const UCHAR 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, 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,
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, 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,
@ -63,12 +64,12 @@ static const UCHAR aucCRCLo[] = {
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,
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,
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,

View File

@ -1,4 +1,4 @@
/*
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
* All rights reserved.
@ -25,6 +25,7 @@
* (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

View File

@ -1,4 +1,4 @@
/*
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
* All rights reserved.
@ -25,6 +25,7 @@
* (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 ----------------------------------*/
@ -130,9 +131,9 @@ eMBRTUStart( void )
* 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( );//启动定时器
eRcvState = STATE_RX_INIT;
vMBPortSerialEnable( TRUE, FALSE );
vMBPortTimersEnable( );
EXIT_CRITICAL_SECTION( );
}
@ -149,11 +150,16 @@ eMBRTUStop( void )
eMBErrorCode
eMBRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength )
{
BOOL xFrameReceived = FALSE;
eMBErrorCode eStatus = MB_ENOERR;
ENTER_CRITICAL_SECTION( );
assert( usRcvBufferPos < MB_SER_PDU_SIZE_MAX );
#ifdef ADD_RTTHREAD_FEATURES
RT_ASSERT( usRcvBufferPos <= MB_SER_PDU_SIZE_MAX );
#endif
#ifdef ADD_XIZI_FEATURES
MB_CHECK( usRcvBufferPos <= MB_SER_PDU_SIZE_MAX );
#endif
/* Length and CRC check */
if( ( usRcvBufferPos >= MB_SER_PDU_SIZE_MIN )
@ -171,7 +177,6 @@ eMBRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength )
/* Return the start of the Modbus PDU to the caller. */
*pucFrame = ( UCHAR * ) & ucRTUBuf[MB_SER_PDU_PDU_OFF];
xFrameReceived = TRUE;
}
else
{
@ -221,16 +226,29 @@ eMBRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength )
return eStatus;
}
#ifdef ADD_RTTHREAD_FEATURES
BOOL
xMBRTUReceiveFSM( void )
#endif
#ifdef ADD_XIZI_FEATURES
BOOL
xMBRTUReceiveFSM( CHAR pucByte )
#endif
{
BOOL xTaskNeedSwitch = FALSE;
UCHAR ucByte;
assert( eSndState == STATE_TX_IDLE );
#ifdef ADD_RTTHREAD_FEATURES
RT_ASSERT( eSndState == STATE_TX_IDLE );
#endif
#ifdef ADD_XIZI_FEATURES
MB_CHECK( eSndState == STATE_TX_IDLE );
#endif
/* Always read the character. */
( void )xMBPortSerialGetByte( ( CHAR * ) & ucByte );
// ( void )xMBPortSerialGetByte( ( CHAR * ) & ucByte );
ucByte = pucByte;
switch ( eRcvState )
{
@ -238,14 +256,14 @@ xMBRTUReceiveFSM( void )
* wait until the frame is finished.
*/
case STATE_RX_INIT:
vMBPortTimersEnable( );
vMBPortTimersEnable( );
break;
/* In the error state we wait until all characters in the
* damaged frame are transmitted.
*/
case STATE_RX_ERROR:
vMBPortTimersEnable( );
vMBPortTimersEnable( );
break;
/* In the idle state we wait for a new character. If a character
@ -253,12 +271,13 @@ xMBRTUReceiveFSM( void )
* receiver is in the state STATE_RX_RECEIVCE.
*/
case STATE_RX_IDLE:
vMBPortTimersDisable( );
usRcvBufferPos = 0;
ucRTUBuf[usRcvBufferPos++] = ucByte;
eRcvState = STATE_RX_RCV;
/* Enable t3.5 timers. */
vMBPortTimersEnable( );
vMBPortTimersEnable( );
break;
/* We are currently receiving a frame. Reset the timer after
@ -275,7 +294,7 @@ xMBRTUReceiveFSM( void )
{
eRcvState = STATE_RX_ERROR;
}
vMBPortTimersEnable( );
//vMBPortTimersEnable();
break;
}
return xTaskNeedSwitch;
@ -286,7 +305,13 @@ xMBRTUTransmitFSM( void )
{
BOOL xNeedPoll = FALSE;
assert( eRcvState == STATE_RX_IDLE );
#ifdef ADD_RTTHREAD_FEATURES
RT_ASSERT( eRcvState == STATE_RX_IDLE );
#endif
#ifdef ADD_XIZI_FEATURES
MB_CHECK( eRcvState == STATE_RX_IDLE );
#endif
switch ( eSndState )
{
@ -318,7 +343,7 @@ xMBRTUTransmitFSM( void )
return xNeedPoll;
}
//定时中断发生,触发的函数
BOOL
xMBRTUTimerT35Expired( void )
{
@ -328,7 +353,7 @@ xMBRTUTimerT35Expired( void )
{
/* Timer t35 expired. Startup phase is finished. */
case STATE_RX_INIT:
xNeedPoll = xMBPortEventPost( EV_READY );//事件类型赋值
xNeedPoll = xMBPortEventPost( EV_READY );
break;
/* A frame was received and t35 expired. Notify the listener that
@ -343,8 +368,16 @@ xMBRTUTimerT35Expired( void )
/* Function called in an illegal state. */
default:
assert( ( eRcvState == STATE_RX_INIT ) ||
#ifdef ADD_RTTHREAD_FEATURES
RT_ASSERT( ( eRcvState == STATE_RX_INIT ) ||
( eRcvState == STATE_RX_RCV ) || ( eRcvState == STATE_RX_ERROR ) );
#endif
#ifdef ADD_XIZI_FEATURES
MB_CHECK( ( eRcvState == STATE_RX_INIT ) ||
( eRcvState == STATE_RX_RCV ) || ( eRcvState == STATE_RX_ERROR ) );
#endif
break;
}
vMBPortTimersDisable( );

View File

@ -1,4 +1,4 @@
/*
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
* All rights reserved.
@ -25,7 +25,10 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbrtu.h,v 1.9 2006/12/07 22:10:34 wolti Exp $
* File: $Id: mbrtu.h,v 1.60 2013/08/17 13:11:42 Armink Add Master Functions $
*/
#include "mbconfig.h"
#ifndef _MB_RTU_H
#define _MB_RTU_H
@ -33,17 +36,38 @@
#ifdef __cplusplus
PR_BEGIN_EXTERN_C
#endif
eMBErrorCode eMBRTUInit( UCHAR slaveAddress, UCHAR ucPort, ULONG ulBaudRate,
eMBParity eParity );
eMBErrorCode eMBRTUInit( UCHAR slaveAddress, UCHAR ucPort, ULONG ulBaudRate,
eMBParity eParity );
void eMBRTUStart( void );
void eMBRTUStop( void );
eMBErrorCode eMBRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength );
eMBErrorCode eMBRTUSend( UCHAR slaveAddress, const UCHAR * pucFrame, USHORT usLength );
#ifdef ADD_RTTHREAD_FEATURES
BOOL xMBRTUReceiveFSM( void );
#endif
#ifdef ADD_XIZI_FEATURES
BOOL xMBRTUReceiveFSM( CHAR pucByte );
#endif
BOOL xMBRTUTransmitFSM( void );
BOOL xMBRTUTimerT15Expired( void );
BOOL xMBRTUTimerT35Expired( void );
#if MB_MASTER_RTU_ENABLED > 0
eMBErrorCode eMBMasterRTUInit( UCHAR ucPort, ULONG ulBaudRate,eMBParity eParity );
void eMBMasterRTUStart( void );
void eMBMasterRTUStop( void );
eMBErrorCode eMBMasterRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength );
eMBErrorCode eMBMasterRTUSend( UCHAR slaveAddress, const UCHAR * pucFrame, USHORT usLength );
BOOL xMBMasterRTUTransmitFSM( void );
#ifdef ADD_RTTHREAD_FEATURES
BOOL xMBMasterRTUReceiveFSM( void );
#endif
#ifdef ADD_XIZI_FEATURES
BOOL xMBMasterRTUReceiveFSM( CHAR pucByte );
#endif
BOOL xMBMasterRTUTimerExpired( void );
#endif
#ifdef __cplusplus
PR_END_EXTERN_C
#endif

View File

@ -0,0 +1,486 @@
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2013 China Beijing Armink <armink.ztl@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* File: $Id: mbrtu_m.c,v 1.60 2013/08/17 11:42:56 Armink Add Master Functions $
*/
/* ----------------------- System includes ----------------------------------*/
#include "stdlib.h"
#include "string.h"
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mb_m.h"
#include "mbrtu.h"
#include "mbframe.h"
#include "mbcrc.h"
#include "mbport.h"
#if MB_MASTER_RTU_ENABLED > 0
/* ----------------------- Defines ------------------------------------------*/
#define MB_SER_PDU_SIZE_MIN 4 /*!< Minimum size of a Modbus RTU frame. */
#define MB_SER_PDU_SIZE_MAX 256 /*!< Maximum size of a Modbus RTU frame. */
#define MB_SER_PDU_SIZE_CRC 2 /*!< Size of CRC field in PDU. */
#define MB_SER_PDU_ADDR_OFF 0 /*!< Offset of slave address in Ser-PDU. */
#define MB_SER_PDU_PDU_OFF 1 /*!< Offset of Modbus-PDU in Ser-PDU. */
/* ----------------------- Type definitions ---------------------------------*/
typedef enum
{
STATE_M_RX_INIT, /*!< Receiver is in initial state. */
STATE_M_RX_IDLE, /*!< Receiver is in idle state. */
STATE_M_RX_RCV, /*!< Frame is beeing received. */
STATE_M_RX_ERROR, /*!< If the frame is invalid. */
} eMBMasterRcvState;
typedef enum
{
STATE_M_TX_IDLE, /*!< Transmitter is in idle state. */
STATE_M_TX_XMIT, /*!< Transmitter is in transfer state. */
STATE_M_TX_XFWR, /*!< Transmitter is in transfer finish and wait receive state. */
} eMBMasterSndState;
/* ----------------------- Static variables ---------------------------------*/
static volatile eMBMasterSndState eSndState;
static volatile eMBMasterRcvState eRcvState;
static volatile UCHAR ucMasterRTUSndBuf[MB_PDU_SIZE_MAX];
static volatile UCHAR ucMasterRTURcvBuf[MB_SER_PDU_SIZE_MAX];
static volatile USHORT usMasterSendPDULength;
static volatile UCHAR *pucMasterSndBufferCur;
static volatile USHORT usMasterSndBufferCount;
static volatile USHORT usMasterRcvBufferPos;
static volatile BOOL xFrameIsBroadcast = FALSE;
static volatile eMBMasterTimerMode eMasterCurTimerMode;
/* ----------------------- Start implementation -----------------------------*/
eMBErrorCode
eMBMasterRTUInit(UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity )
{
eMBErrorCode eStatus = MB_ENOERR;
ULONG usTimerT35_50us;
ENTER_CRITICAL_SECTION( );
/* Modbus RTU uses 8 Databits. */
if( xMBMasterPortSerialInit( ucPort, ulBaudRate, 8, eParity ) != TRUE )
{
eStatus = MB_EPORTERR;
}
else
{
/* If baudrate > 19200 then we should use the fixed timer values
* t35 = 1750us. Otherwise t35 must be 3.5 times the character time.
*/
if( ulBaudRate > 19200 )
{
usTimerT35_50us = 35; /* 1800us. */
}
else
{
/* The timer reload value for a character is given by:
*
* ChTimeValue = Ticks_per_1s / ( Baudrate / 11 )
* = 11 * Ticks_per_1s / Baudrate
* = 220000 / Baudrate
* The reload for t3.5 is 1.5 times this value and similary
* for t3.5.
*/
usTimerT35_50us = ( 7UL * 220000UL ) / ( 2UL * ulBaudRate );
}
if( xMBMasterPortTimersInit( ( USHORT ) usTimerT35_50us ) != TRUE )
{
eStatus = MB_EPORTERR;
}
}
EXIT_CRITICAL_SECTION( );
return eStatus;
}
void
eMBMasterRTUStart( void )
{
ENTER_CRITICAL_SECTION( );
/* Initially the receiver is in the state STATE_M_RX_INIT. we start
* the timer and if no character is received within t3.5 we change
* to STATE_M_RX_IDLE. This makes sure that we delay startup of the
* modbus protocol stack until the bus is free.
*/
eRcvState = STATE_M_RX_INIT;
vMBMasterPortSerialEnable( TRUE, FALSE );
vMBMasterPortTimersT35Enable( );
EXIT_CRITICAL_SECTION( );
}
void
eMBMasterRTUStop( void )
{
ENTER_CRITICAL_SECTION( );
vMBMasterPortSerialEnable( FALSE, FALSE );
vMBMasterPortTimersDisable( );
EXIT_CRITICAL_SECTION( );
}
eMBErrorCode
eMBMasterRTUReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength )
{
eMBErrorCode eStatus = MB_ENOERR;
ENTER_CRITICAL_SECTION( );
#ifdef ADD_RTTHREAD_FEATURES
RT_ASSERT( usMasterRcvBufferPos < MB_SER_PDU_SIZE_MAX );
#endif
#ifdef ADD_XIZI_FEATURES
MB_CHECK( usMasterRcvBufferPos < MB_SER_PDU_SIZE_MAX );
#endif
/* Length and CRC check */
if( ( usMasterRcvBufferPos >= MB_SER_PDU_SIZE_MIN )
&& ( usMBCRC16( ( UCHAR * ) ucMasterRTURcvBuf, usMasterRcvBufferPos ) == 0 ) )
{
/* Save the address field. All frames are passed to the upper layed
* and the decision if a frame is used is done there.
*/
*pucRcvAddress = ucMasterRTURcvBuf[MB_SER_PDU_ADDR_OFF];
/* Total length of Modbus-PDU is Modbus-Serial-Line-PDU minus
* size of address field and CRC checksum.
*/
*pusLength = ( USHORT )( usMasterRcvBufferPos - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_CRC );
/* Return the start of the Modbus PDU to the caller. */
*pucFrame = ( UCHAR * ) & ucMasterRTURcvBuf[MB_SER_PDU_PDU_OFF];
}
else
{
eStatus = MB_EIO;
}
EXIT_CRITICAL_SECTION( );
return eStatus;
}
eMBErrorCode
eMBMasterRTUSend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength )
{
eMBErrorCode eStatus = MB_ENOERR;
USHORT usCRC16;
if ( ucSlaveAddress > MB_MASTER_TOTAL_SLAVE_NUM ) return MB_EINVAL;
ENTER_CRITICAL_SECTION( );
/* Check if the receiver is still in idle state. If not we where to
* slow with processing the received frame and the master sent another
* frame on the network. We have to abort sending the frame.
*/
if( eRcvState == STATE_M_RX_IDLE )
{
/* First byte before the Modbus-PDU is the slave address. */
pucMasterSndBufferCur = ( UCHAR * ) pucFrame - 1;
usMasterSndBufferCount = 1;
/* Now copy the Modbus-PDU into the Modbus-Serial-Line-PDU. */
pucMasterSndBufferCur[MB_SER_PDU_ADDR_OFF] = ucSlaveAddress;
usMasterSndBufferCount += usLength;
/* Calculate CRC16 checksum for Modbus-Serial-Line-PDU. */
usCRC16 = usMBCRC16( ( UCHAR * ) pucMasterSndBufferCur, usMasterSndBufferCount );
ucMasterRTUSndBuf[usMasterSndBufferCount++] = ( UCHAR )( usCRC16 & 0xFF );
ucMasterRTUSndBuf[usMasterSndBufferCount++] = ( UCHAR )( usCRC16 >> 8 );
/* Activate the transmitter. */
eSndState = STATE_M_TX_XMIT;
vMBMasterPortSerialEnable( FALSE, TRUE );
}
else
{
eStatus = MB_EIO;
}
EXIT_CRITICAL_SECTION( );
return eStatus;
}
#ifdef ADD_RTTHREAD_FEATURES
BOOL
xMBMasterRTUReceiveFSM( void )
#endif
#ifdef ADD_XIZI_FEATURES
BOOL
xMBMasterRTUReceiveFSM( CHAR pucByte )
#endif
{
BOOL xTaskNeedSwitch = FALSE;
UCHAR ucByte;
#ifdef ADD_RTTHREAD_FEATURES
RT_ASSERT(( eSndState == STATE_M_TX_IDLE ) || ( eSndState == STATE_M_TX_XFWR ));
#endif
#ifdef ADD_XIZI_FEATURES
MB_CHECK(( eSndState == STATE_M_TX_IDLE ) || ( eSndState == STATE_M_TX_XFWR ));
#endif
// /* Always read the character. */
// ( void )xMBMasterPortSerialGetByte( ( CHAR * ) & ucByte );
ucByte = pucByte;
switch ( eRcvState )
{
/* If we have received a character in the init state we have to
* wait until the frame is finished.
*/
case STATE_M_RX_INIT:
vMBMasterPortTimersT35Enable( );
break;
/* In the error state we wait until all characters in the
* damaged frame are transmitted.
*/
case STATE_M_RX_ERROR:
vMBMasterPortTimersT35Enable( );
break;
/* In the idle state we wait for a new character. If a character
* is received the t1.5 and t3.5 timers are started and the
* receiver is in the state STATE_RX_RECEIVCE and disable early
* the timer of respond timeout .
*/
case STATE_M_RX_IDLE:
/* In time of respond timeout,the receiver receive a frame.
* Disable timer of respond timeout and change the transmiter state to idle.
*/
vMBMasterPortTimersDisable( );
eSndState = STATE_M_TX_IDLE;
usMasterRcvBufferPos = 0;
ucMasterRTURcvBuf[usMasterRcvBufferPos++] = ucByte;
eRcvState = STATE_M_RX_RCV;
/* Enable t3.5 timers. */
vMBMasterPortTimersT35Enable( );
break;
/* We are currently receiving a frame. Reset the timer after
* every character received. If more than the maximum possible
* number of bytes in a modbus frame is received the frame is
* ignored.
*/
case STATE_M_RX_RCV:
if( usMasterRcvBufferPos < MB_SER_PDU_SIZE_MAX )
{
ucMasterRTURcvBuf[usMasterRcvBufferPos++] = ucByte;
}
else
{
eRcvState = STATE_M_RX_ERROR;
}
//vMBMasterPortTimersT35Enable();
break;
}
return xTaskNeedSwitch;
}
BOOL
xMBMasterRTUTransmitFSM( void )
{
BOOL xNeedPoll = FALSE;
#ifdef ADD_RTTHREAD_FEATURES
RT_ASSERT( eRcvState == STATE_M_RX_IDLE );
#endif
#ifdef ADD_XIZI_FEATURES
MB_CHECK( eRcvState == STATE_M_RX_IDLE );
#endif
switch ( eSndState )
{
/* We should not get a transmitter event if the transmitter is in
* idle state. */
case STATE_M_TX_IDLE:
/* enable receiver/disable transmitter. */
vMBMasterPortSerialEnable( TRUE, FALSE );
break;
case STATE_M_TX_XMIT:
/* check if we are finished. */
if( usMasterSndBufferCount != 0 )
{
xMBMasterPortSerialPutByte( ( CHAR )*pucMasterSndBufferCur );
pucMasterSndBufferCur++; /* next byte in sendbuffer. */
usMasterSndBufferCount--;
}
else
{
xFrameIsBroadcast = ( ucMasterRTUSndBuf[MB_SER_PDU_ADDR_OFF] == MB_ADDRESS_BROADCAST ) ? TRUE : FALSE;
/* Disable transmitter. This prevents another transmit buffer
* empty interrupt. */
vMBMasterPortSerialEnable( TRUE, FALSE );
eSndState = STATE_M_TX_XFWR;
/* If the frame is broadcast ,master will enable timer of convert delay,
* else master will enable timer of respond timeout. */
if ( xFrameIsBroadcast == TRUE )
{
vMBMasterPortTimersConvertDelayEnable( );
}
else
{
vMBMasterPortTimersRespondTimeoutEnable( );
}
}
break;
default:
break;
}
return xNeedPoll;
}
BOOL
xMBMasterRTUTimerExpired(void)
{
BOOL xNeedPoll = FALSE;
switch (eRcvState)
{
/* Timer t35 expired. Startup phase is finished. */
case STATE_M_RX_INIT:
xNeedPoll = xMBMasterPortEventPost(EV_MASTER_READY);
break;
/* A frame was received and t35 expired. Notify the listener that
* a new frame was received. */
case STATE_M_RX_RCV:
xNeedPoll = xMBMasterPortEventPost(EV_MASTER_FRAME_RECEIVED);
break;
/* An error occured while receiving the frame. */
case STATE_M_RX_ERROR:
vMBMasterSetErrorType(EV_ERROR_RECEIVE_DATA);
xNeedPoll = xMBMasterPortEventPost( EV_MASTER_ERROR_PROCESS );
break;
/* Function called in an illegal state. */
default:
#ifdef ADD_RTTHREAD_FEATURES
RT_ASSERT(
( eRcvState == STATE_M_RX_INIT ) || ( eRcvState == STATE_M_RX_RCV ) ||
( eRcvState == STATE_M_RX_ERROR ) || ( eRcvState == STATE_M_RX_IDLE ));
#endif
#ifdef ADD_XIZI_FEATURES
MB_CHECK(
( eRcvState == STATE_M_RX_INIT ) || ( eRcvState == STATE_M_RX_RCV ) ||
( eRcvState == STATE_M_RX_ERROR ) || ( eRcvState == STATE_M_RX_IDLE ));
#endif
break;
}
eRcvState = STATE_M_RX_IDLE;
switch (eSndState)
{
/* A frame was send finish and convert delay or respond timeout expired.
* If the frame is broadcast,The master will idle,and if the frame is not
* broadcast.Notify the listener process error.*/
case STATE_M_TX_XFWR:
if ( xFrameIsBroadcast == FALSE ) {
vMBMasterSetErrorType(EV_ERROR_RESPOND_TIMEOUT);
xNeedPoll = xMBMasterPortEventPost(EV_MASTER_ERROR_PROCESS);
}
break;
/* Function called in an illegal state. */
default:
#ifdef ADD_RTTHREAD_FEATURES
RT_ASSERT(
( eSndState == STATE_M_TX_XFWR ) || ( eSndState == STATE_M_TX_IDLE ));
#endif
#ifdef ADD_XIZI_FEATURES
MB_CHECK(
( eSndState == STATE_M_TX_XFWR ) || ( eSndState == STATE_M_TX_IDLE ));
#endif
break;
}
eSndState = STATE_M_TX_IDLE;
vMBMasterPortTimersDisable( );
/* If timer mode is convert delay, the master event then turns EV_MASTER_EXECUTE status. */
if (eMasterCurTimerMode == MB_TMODE_CONVERT_DELAY) {
xNeedPoll = xMBMasterPortEventPost( EV_MASTER_EXECUTE );
}
return xNeedPoll;
}
/* Get Modbus Master send RTU's buffer address pointer.*/
void vMBMasterGetRTUSndBuf( UCHAR ** pucFrame )
{
*pucFrame = ( UCHAR * ) ucMasterRTUSndBuf;
}
/* Get Modbus Master send PDU's buffer address pointer.*/
void vMBMasterGetPDUSndBuf( UCHAR ** pucFrame )
{
*pucFrame = ( UCHAR * ) &ucMasterRTUSndBuf[MB_SER_PDU_PDU_OFF];
}
/* Set Modbus Master send PDU's buffer length.*/
void vMBMasterSetPDUSndLength( USHORT SendPDULength )
{
usMasterSendPDULength = SendPDULength;
}
/* Get Modbus Master send PDU's buffer length.*/
USHORT usMBMasterGetPDUSndLength( void )
{
return usMasterSendPDULength;
}
/* Set Modbus Master current timer mode.*/
void vMBMasterSetCurTimerMode( eMBMasterTimerMode eMBTimerMode )
{
eMasterCurTimerMode = eMBTimerMode;
}
/* The master request is broadcast? */
BOOL xMBMasterRequestIsBroadcast( void ){
return xFrameIsBroadcast;
}
#endif

View File

@ -0,0 +1,5 @@
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_TCP_SLAVE),y)
SRC_FILES := mbtcp.c
endif
include $(KERNEL_ROOT)/compiler.mk

View File

@ -1,4 +1,4 @@
/*
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
* All rights reserved.
@ -25,6 +25,7 @@
* (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 ----------------------------------*/
@ -41,7 +42,7 @@
#include "mbframe.h"
#include "mbport.h"
#if MB_TCP_ENABLED > 0
#if MB_SLAVE_TCP_ENABLED > 0
/* ----------------------- Defines ------------------------------------------*/
@ -53,10 +54,10 @@
* +-----------+---------------+------------------------------------------+
* | TID | PID | Length | UID |Code | Data |
* +-----------+---------------+------------------------------------------+
* | | | | |
* (2) (3) (4) (5) (6)
* | | | | |
* (2) (3) (4) (5) (6)
*
* (2) ... MB_TCP_TID = 0 (Transaction Identifier - 2 Byte)
* (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)
@ -140,9 +141,9 @@ eMBTCPSend( UCHAR _unused, const UCHAR * pucFrame, USHORT usLength )
USHORT usTCPLength = usLength + MB_TCP_FUNC;
/* The MBAP header is already initialized because the caller calls this
* function with the buffer returned by the previous call. Therefore we
* only have to update the length in the header. Note that the length
* header includes the size of the Modbus PDU and the UID Byte. Therefore
* 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;

View File

@ -1,4 +1,4 @@
/*
/*
* FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
* Copyright (c) 2006-2018 Christian Walter <cwalter@embedded-solutions.at>
* All rights reserved.
@ -25,6 +25,7 @@
* (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

View File

@ -0,0 +1,15 @@
SRC_FILES := port.c
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_RTU_MASTER),y)
SRC_FILES += portevent_m.c portserial_m.c porttimer_m.c user_mb_app_m.c
endif
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_RTU_SLAVE),y)
SRC_FILES += portevent.c portserial.c porttimer.c user_mb_app.c
endif
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_TCP_SLAVE),y)
SRC_FILES += porttcp.c portevent.c porttimer.c user_mb_app.c
endif
include $(KERNEL_ROOT)/compiler.mk

View File

@ -0,0 +1,92 @@
/*
* FreeModbus Libary: RT-Thread Port
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id: port.c,v 1.60 2015/02/01 9:18:05 Armink $
*/
/**
* @file port.c
* @brief support freemodbus port for XiUOS
* @version 3.0
* @author AIIT XUOS Lab
* @date 2023-10-12
*/
/*************************************************
File name: port.c
Description: support freemodbus port for XiUOS
Others:
History:
1. Date: 2023-10-12
Author: AIIT XUOS Lab
Modification:
1support XiUOS sem.
*************************************************/
/* ----------------------- System includes --------------------------------*/
/* ----------------------- Modbus includes ----------------------------------*/
#include "port.h"
/* ----------------------- Variables ----------------------------------------*/
#ifdef ADD_RTTHREAD_FEATURES
static struct rt_semaphore lock;
#endif
#ifdef ADD_XIZI_FEATURES
static sem_t sem;
#endif
static int is_inited = 0;
/* ----------------------- Start implementation -----------------------------*/
#ifdef ADD_RTTHREAD_FEATURES
void EnterCriticalSection(void)
{
rt_err_t err;
if(!is_inited)
{
err = rt_sem_init(&lock, "fmb_lock", 1, RT_IPC_FLAG_PRIO);
if(err != RT_EOK)
{
rt_kprintf("Freemodbus Critical init failed!\n");
}
is_inited = 1;
}
rt_sem_take(&lock, RT_WAITING_FOREVER);
}
void ExitCriticalSection(void)
{
rt_sem_release(&lock);
}
#endif
#ifdef ADD_XIZI_FEATURES
void EnterCriticalSection(void)
{
if(!is_inited) {
PrivSemaphoreCreate(&sem, 0, 1);
is_inited = 1;
}
PrivSemaphoreObtainWait(&sem, NULL);
}
void ExitCriticalSection(void)
{
PrivSemaphoreAbandon(&sem);
}
#endif

View File

@ -0,0 +1,95 @@
/*
* FreeModbus Libary: BARE Port
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id: port.h ,v 1.60 2013/08/13 15:07:05 Armink add Master Functions $
*/
/**
* @file port.h
* @brief support freemodbus port for XiUOS
* @version 3.0
* @author AIIT XUOS Lab
* @date 2023-10-12
*/
/*************************************************
File name: port.h
Description: support freemodbus port for XiUOS
Others:
History:
1. Date: 2023-10-12
Author: AIIT XUOS Lab
Modification:
1add transform.h to support XiUOS.
*************************************************/
#ifndef _PORT_H
#define _PORT_H
#include <transform.h>
#include "mbconfig.h"
#ifdef ADD_RTTHREAD_FEATURES
#include <rthw.h>
#include <rtthread.h>
#endif
#include <assert.h>
#include <inttypes.h>
#define INLINE
#define PR_BEGIN_EXTERN_C extern "C" {
#define PR_END_EXTERN_C }
#define ENTER_CRITICAL_SECTION() EnterCriticalSection()
#define EXIT_CRITICAL_SECTION() ExitCriticalSection()
typedef uint8_t BOOL;
typedef unsigned char UCHAR;
typedef char CHAR;
typedef uint16_t USHORT;
typedef int16_t SHORT;
typedef uint32_t ULONG;
typedef int32_t LONG;
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifdef ADD_XIZI_FEATURES
#define MB_CHECK(TRUE_CONDITION) \
do { \
if (!(TRUE_CONDITION)) { \
KPrintf("%s CHECK condition is false at line[%d] of [%s] func.\n", #TRUE_CONDITION, __LINE__, __FUNCTION__); \
while (RET_TRUE) \
; \
} \
} while (0)
#endif
void EnterCriticalSection(void);
void ExitCriticalSection(void);
#endif

View File

@ -0,0 +1,136 @@
/*
* FreeModbus Libary: RT-Thread Port
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id: portevent.c,v 1.60 2013/08/13 15:07:05 Armink $
*/
/**
* @file portevent.c
* @brief support freemodbus port for XiUOS
* @version 3.0
* @author AIIT XUOS Lab
* @date 2023-10-12
*/
/*************************************************
File name: portevent.c
Description: support freemodbus port for XiUOS
Others:
History:
1. Date: 2023-10-12
Author: AIIT XUOS Lab
Modification:
1support XiUOS event for slave.
*************************************************/
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
#ifdef ADD_RTTHREAD_FEATURES
/* ----------------------- Variables ----------------------------------------*/
static struct rt_event xSlaveOsEvent;
/* ----------------------- Start implementation -----------------------------*/
BOOL
xMBPortEventInit( void )
{
rt_event_init(&xSlaveOsEvent,"slave event",RT_IPC_FLAG_PRIO);
return TRUE;
}
BOOL
xMBPortEventPost( eMBEventType eEvent )
{
rt_event_send(&xSlaveOsEvent, eEvent);
return TRUE;
}
BOOL
xMBPortEventGet( eMBEventType * eEvent )
{
rt_uint32_t recvedEvent;
/* waiting forever OS event */
rt_event_recv(&xSlaveOsEvent,
EV_READY | EV_FRAME_RECEIVED | EV_EXECUTE | EV_FRAME_SENT,
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER,
&recvedEvent);
switch (recvedEvent)
{
case EV_READY:
*eEvent = EV_READY;
break;
case EV_FRAME_RECEIVED:
*eEvent = EV_FRAME_RECEIVED;
break;
case EV_EXECUTE:
*eEvent = EV_EXECUTE;
break;
case EV_FRAME_SENT:
*eEvent = EV_FRAME_SENT;
break;
}
return TRUE;
}
#endif
#ifdef ADD_XIZI_FEATURES
/* ----------------------- Variables ----------------------------------------*/
static int xSlaveOsEvent;
/* ----------------------- Start implementation -----------------------------*/
BOOL
xMBPortEventInit( void )
{
xSlaveOsEvent = PrivEventCreate(LINKLIST_FLAG_PRIO);
return TRUE;
}
BOOL
xMBPortEventPost( eMBEventType eEvent )
{
PrivEvenTrigger(xSlaveOsEvent, eEvent);
return TRUE;
}
BOOL
xMBPortEventGet( eMBEventType * eEvent )
{
unsigned int recvedEvent;
/* waiting forever OS event */
PrivEventProcess(xSlaveOsEvent,
EV_READY | EV_FRAME_RECEIVED | EV_EXECUTE | EV_FRAME_SENT,
EVENT_OR | EVENT_AUTOCLEAN, 0, &recvedEvent);
switch (recvedEvent)
{
case EV_READY:
*eEvent = EV_READY;
break;
case EV_FRAME_RECEIVED:
*eEvent = EV_FRAME_RECEIVED;
break;
case EV_EXECUTE:
*eEvent = EV_EXECUTE;
break;
case EV_FRAME_SENT:
*eEvent = EV_FRAME_SENT;
break;
}
return TRUE;
}
#endif

View File

@ -0,0 +1,483 @@
/*
* FreeModbus Libary: RT-Thread Port
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id: portevent_m.c v 1.60 2013/08/13 15:07:05 Armink add Master Functions$
*/
/**
* @file portevent_m.c
* @brief support freemodbus port for XiUOS
* @version 3.0
* @author AIIT XUOS Lab
* @date 2023-10-12
*/
/*************************************************
File name: portevent_m.c
Description: support freemodbus port for XiUOS
Others:
History:
1. Date: 2023-10-12
Author: AIIT XUOS Lab
Modification:
1support XiUOS event for master.
*************************************************/
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mb_m.h"
#include "mbport.h"
#include "port.h"
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
#ifdef ADD_RTTHREAD_FEATURES
/* ----------------------- Defines ------------------------------------------*/
/* ----------------------- Variables ----------------------------------------*/
static struct rt_semaphore xMasterRunRes;
static struct rt_event xMasterOsEvent;
/* ----------------------- Start implementation -----------------------------*/
BOOL
xMBMasterPortEventInit( void )
{
rt_event_init(&xMasterOsEvent,"master event",RT_IPC_FLAG_PRIO);
return TRUE;
}
BOOL
xMBMasterPortEventPost( eMBMasterEventType eEvent )
{
rt_event_send(&xMasterOsEvent, eEvent);
return TRUE;
}
BOOL
xMBMasterPortEventGet( eMBMasterEventType * eEvent )
{
rt_uint32_t recvedEvent;
/* waiting forever OS event */
rt_event_recv(&xMasterOsEvent,
EV_MASTER_READY | EV_MASTER_FRAME_RECEIVED | EV_MASTER_EXECUTE |
EV_MASTER_FRAME_SENT | EV_MASTER_ERROR_PROCESS,
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER,
&recvedEvent);
/* the enum type couldn't convert to int type */
switch (recvedEvent)
{
case EV_MASTER_READY:
*eEvent = EV_MASTER_READY;
break;
case EV_MASTER_FRAME_RECEIVED:
*eEvent = EV_MASTER_FRAME_RECEIVED;
break;
case EV_MASTER_EXECUTE:
*eEvent = EV_MASTER_EXECUTE;
break;
case EV_MASTER_FRAME_SENT:
*eEvent = EV_MASTER_FRAME_SENT;
break;
case EV_MASTER_ERROR_PROCESS:
*eEvent = EV_MASTER_ERROR_PROCESS;
break;
default:
*eEvent = EV_MASTER_FRAME_RECEIVED;
break;
}
return TRUE;
}
/**
* This function is initialize the OS resource for modbus master.
* Note:The resource is define by OS.If you not use OS this function can be empty.
*
*/
void vMBMasterOsResInit( void )
{
rt_sem_init(&xMasterRunRes, "master res", 0x01 , RT_IPC_FLAG_PRIO);
}
/**
* This function is take Mobus Master running resource.
* Note:The resource is define by Operating System.If you not use OS this function can be just return TRUE.
*
* @param lTimeOut the waiting time.
*
* @return resource taked result
*/
BOOL xMBMasterRunResTake( LONG lTimeOut )
{
/*If waiting time is -1 .It will wait forever */
return rt_sem_take(&xMasterRunRes, lTimeOut) ? FALSE : TRUE ;
}
/**
* This function is release Mobus Master running resource.
* Note:The resource is define by Operating System.If you not use OS this function can be empty.
*
*/
void vMBMasterRunResRelease( void )
{
/* release resource */
rt_sem_release(&xMasterRunRes);
}
/**
* This is modbus master respond timeout error process callback function.
* @note There functions will block modbus master poll while execute OS waiting.
* So,for real-time of system.Do not execute too much waiting process.
*
* @param ucDestAddress destination salve address
* @param pucPDUData PDU buffer data
* @param ucPDULength PDU buffer length
*
*/
void vMBMasterErrorCBRespondTimeout(UCHAR ucDestAddress, const UCHAR* pucPDUData,
USHORT ucPDULength) {
/**
* @note This code is use OS's event mechanism for modbus master protocol stack.
* If you don't use OS, you can change it.
*/
rt_event_send(&xMasterOsEvent, EV_MASTER_ERROR_RESPOND_TIMEOUT);
/* You can add your code under here. */
}
/**
* This is modbus master receive data error process callback function.
* @note There functions will block modbus master poll while execute OS waiting.
* So,for real-time of system.Do not execute too much waiting process.
*
* @param ucDestAddress destination salve address
* @param pucPDUData PDU buffer data
* @param ucPDULength PDU buffer length
*
*/
void vMBMasterErrorCBReceiveData(UCHAR ucDestAddress, const UCHAR* pucPDUData,
USHORT ucPDULength) {
/**
* @note This code is use OS's event mechanism for modbus master protocol stack.
* If you don't use OS, you can change it.
*/
rt_event_send(&xMasterOsEvent, EV_MASTER_ERROR_RECEIVE_DATA);
/* You can add your code under here. */
}
/**
* This is modbus master execute function error process callback function.
* @note There functions will block modbus master poll while execute OS waiting.
* So,for real-time of system.Do not execute too much waiting process.
*
* @param ucDestAddress destination salve address
* @param pucPDUData PDU buffer data
* @param ucPDULength PDU buffer length
*
*/
void vMBMasterErrorCBExecuteFunction(UCHAR ucDestAddress, const UCHAR* pucPDUData,
USHORT ucPDULength) {
/**
* @note This code is use OS's event mechanism for modbus master protocol stack.
* If you don't use OS, you can change it.
*/
rt_event_send(&xMasterOsEvent, EV_MASTER_ERROR_EXECUTE_FUNCTION);
/* You can add your code under here. */
}
/**
* This is modbus master request process success callback function.
* @note There functions will block modbus master poll while execute OS waiting.
* So,for real-time of system.Do not execute too much waiting process.
*
*/
void vMBMasterCBRequestScuuess( void ) {
/**
* @note This code is use OS's event mechanism for modbus master protocol stack.
* If you don't use OS, you can change it.
*/
rt_event_send(&xMasterOsEvent, EV_MASTER_PROCESS_SUCESS);
/* You can add your code under here. */
}
/**
* This function is wait for modbus master request finish and return result.
* Waiting result include request process success, request respond timeout,
* receive data error and execute function error.You can use the above callback function.
* @note If you are use OS, you can use OS's event mechanism. Otherwise you have to run
* much user custom delay for waiting.
*
* @return request error code
*/
eMBMasterReqErrCode eMBMasterWaitRequestFinish( void ) {
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
rt_uint32_t recvedEvent;
/* waiting for OS event */
rt_event_recv(&xMasterOsEvent,
EV_MASTER_PROCESS_SUCESS | EV_MASTER_ERROR_RESPOND_TIMEOUT
| EV_MASTER_ERROR_RECEIVE_DATA
| EV_MASTER_ERROR_EXECUTE_FUNCTION,
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER,
&recvedEvent);
switch (recvedEvent)
{
case EV_MASTER_PROCESS_SUCESS:
break;
case EV_MASTER_ERROR_RESPOND_TIMEOUT:
{
eErrStatus = MB_MRE_TIMEDOUT;
break;
}
case EV_MASTER_ERROR_RECEIVE_DATA:
{
eErrStatus = MB_MRE_REV_DATA;
break;
}
case EV_MASTER_ERROR_EXECUTE_FUNCTION:
{
eErrStatus = MB_MRE_EXE_FUN;
break;
}
}
return eErrStatus;
}
#endif
#ifdef ADD_XIZI_FEATURES
/* ----------------------- Defines ------------------------------------------*/
/* ----------------------- Variables ----------------------------------------*/
static sem_t xMasterRunRes;
static int xMasterOsEvent;
/* ----------------------- Start implementation -----------------------------*/
BOOL
xMBMasterPortEventInit( void )
{
xMasterOsEvent = PrivEventCreate(LINKLIST_FLAG_PRIO);
return TRUE;
}
BOOL
xMBMasterPortEventPost( eMBMasterEventType eEvent )
{
PrivEvenTrigger(xMasterOsEvent, eEvent);
return TRUE;
}
BOOL
xMBMasterPortEventGet( eMBMasterEventType * eEvent )
{
unsigned int recvedEvent = EV_MASTER_ERROR_PROCESS;
/* waiting forever OS event */
PrivEventProcess(xMasterOsEvent,
EV_MASTER_READY | EV_MASTER_FRAME_RECEIVED | EV_MASTER_EXECUTE |
EV_MASTER_FRAME_SENT | EV_MASTER_ERROR_PROCESS,
EVENT_OR | EVENT_AUTOCLEAN, 0, &recvedEvent);
/* the enum type couldn't convert to int type */
switch (recvedEvent)
{
case EV_MASTER_READY:
*eEvent = EV_MASTER_READY;
break;
case EV_MASTER_FRAME_RECEIVED:
*eEvent = EV_MASTER_FRAME_RECEIVED;
break;
case EV_MASTER_EXECUTE:
*eEvent = EV_MASTER_EXECUTE;
break;
case EV_MASTER_FRAME_SENT:
*eEvent = EV_MASTER_FRAME_SENT;
break;
case EV_MASTER_ERROR_PROCESS:
*eEvent = EV_MASTER_ERROR_PROCESS;
break;
default:
*eEvent = EV_MASTER_FRAME_RECEIVED;
break;
}
return TRUE;
}
/**
* This function is initialize the OS resource for modbus master.
* Note:The resource is define by OS.If you not use OS this function can be empty.
*
*/
void vMBMasterOsResInit( void )
{
PrivSemaphoreCreate(&xMasterRunRes, 0, 1);
}
/**
* This function is take Mobus Master running resource.
* Note:The resource is define by Operating System.If you not use OS this function can be just return TRUE.
*
* @param lTimeOut the waiting time.
*
* @return resource taked result
*/
BOOL xMBMasterRunResTake( LONG lTimeOut )
{
/*If waiting time is -1 .It will wait forever */
return PrivSemaphoreObtainWait(&xMasterRunRes, NULL) ? FALSE : TRUE ;
}
/**
* This function is release Mobus Master running resource.
* Note:The resource is define by Operating System.If you not use OS this function can be empty.
*
*/
void vMBMasterRunResRelease( void )
{
/* release resource */
PrivSemaphoreAbandon(&xMasterRunRes);
}
/**
* This is modbus master respond timeout error process callback function.
* @note There functions will block modbus master poll while execute OS waiting.
* So,for real-time of system.Do not execute too much waiting process.
*
* @param ucDestAddress destination salve address
* @param pucPDUData PDU buffer data
* @param ucPDULength PDU buffer length
*
*/
void vMBMasterErrorCBRespondTimeout(UCHAR ucDestAddress, const UCHAR* pucPDUData,
USHORT ucPDULength) {
/**
* @note This code is use OS's event mechanism for modbus master protocol stack.
* If you don't use OS, you can change it.
*/
PrivEvenTrigger(xMasterOsEvent, EV_MASTER_ERROR_RESPOND_TIMEOUT);
/* You can add your code under here. */
}
/**
* This is modbus master receive data error process callback function.
* @note There functions will block modbus master poll while execute OS waiting.
* So,for real-time of system.Do not execute too much waiting process.
*
* @param ucDestAddress destination salve address
* @param pucPDUData PDU buffer data
* @param ucPDULength PDU buffer length
*
*/
void vMBMasterErrorCBReceiveData(UCHAR ucDestAddress, const UCHAR* pucPDUData,
USHORT ucPDULength) {
/**
* @note This code is use OS's event mechanism for modbus master protocol stack.
* If you don't use OS, you can change it.
*/
PrivEvenTrigger(xMasterOsEvent, EV_MASTER_ERROR_RECEIVE_DATA);
/* You can add your code under here. */
}
/**
* This is modbus master execute function error process callback function.
* @note There functions will block modbus master poll while execute OS waiting.
* So,for real-time of system.Do not execute too much waiting process.
*
* @param ucDestAddress destination salve address
* @param pucPDUData PDU buffer data
* @param ucPDULength PDU buffer length
*
*/
void vMBMasterErrorCBExecuteFunction(UCHAR ucDestAddress, const UCHAR* pucPDUData,
USHORT ucPDULength) {
/**
* @note This code is use OS's event mechanism for modbus master protocol stack.
* If you don't use OS, you can change it.
*/
PrivEvenTrigger(xMasterOsEvent, EV_MASTER_ERROR_EXECUTE_FUNCTION);
/* You can add your code under here. */
}
/**
* This is modbus master request process success callback function.
* @note There functions will block modbus master poll while execute OS waiting.
* So,for real-time of system.Do not execute too much waiting process.
*
*/
void vMBMasterCBRequestScuuess( void ) {
/**
* @note This code is use OS's event mechanism for modbus master protocol stack.
* If you don't use OS, you can change it.
*/
PrivEvenTrigger(xMasterOsEvent, EV_MASTER_PROCESS_SUCESS);
/* You can add your code under here. */
}
/**
* This function is wait for modbus master request finish and return result.
* Waiting result include request process success, request respond timeout,
* receive data error and execute function error.You can use the above callback function.
* @note If you are use OS, you can use OS's event mechanism. Otherwise you have to run
* much user custom delay for waiting.
*
* @return request error code
*/
eMBMasterReqErrCode eMBMasterWaitRequestFinish( void ) {
eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
unsigned int recvedEvent;
/* waiting forever OS event */
PrivEventProcess(xMasterOsEvent,
EV_MASTER_PROCESS_SUCESS | EV_MASTER_ERROR_RESPOND_TIMEOUT
| EV_MASTER_ERROR_RECEIVE_DATA
| EV_MASTER_ERROR_EXECUTE_FUNCTION,
EVENT_OR | EVENT_AUTOCLEAN, 0, &recvedEvent);
switch (recvedEvent)
{
case EV_MASTER_PROCESS_SUCESS:
break;
case EV_MASTER_ERROR_RESPOND_TIMEOUT:
{
eErrStatus = MB_MRE_TIMEDOUT;
break;
}
case EV_MASTER_ERROR_RECEIVE_DATA:
{
eErrStatus = MB_MRE_REV_DATA;
break;
}
case EV_MASTER_ERROR_EXECUTE_FUNCTION:
{
eErrStatus = MB_MRE_EXE_FUN;
break;
}
}
return eErrStatus;
}
#endif
#endif

View File

@ -0,0 +1,509 @@
/*
* FreeModbus Libary: RT-Thread Port
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id: portserial.c,v 1.60 2013/08/13 15:07:05 Armink $
*/
/**
* @file portserial.c
* @brief support freemodbus port for XiUOS
* @version 3.0
* @author AIIT XUOS Lab
* @date 2023-10-12
*/
/*************************************************
File name: portserial.c
Description: support freemodbus port for XiUOS
Others:
History:
1. Date: 2023-10-12
Author: AIIT XUOS Lab
Modification:
1support XiUOS serial for slave.
*************************************************/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
#ifdef ADD_RTTHREAD_FEATURES
#include "rtdevice.h"
#include "board.h"
/* ----------------------- Static variables ---------------------------------*/
/* software simulation serial transmit IRQ handler thread stack */
#ifdef rt_align
rt_align(RT_ALIGN_SIZE)
#else
ALIGN(RT_ALIGN_SIZE)
#endif
static rt_uint8_t serial_soft_trans_irq_stack[512];
/* software simulation serial transmit IRQ handler thread */
static struct rt_thread thread_serial_soft_trans_irq;
/* serial event */
static struct rt_event event_serial;
/* modbus slave serial device */
static struct rt_serial_device *serial;
/* ----------------------- Defines ------------------------------------------*/
/* serial transmit event */
#define EVENT_SERIAL_TRANS_START (1<<0)
/* ----------------------- static functions ---------------------------------*/
static void prvvUARTTxReadyISR(void);
static void prvvUARTRxISR(void);
static rt_err_t serial_rx_ind(rt_device_t dev, rt_size_t size);
static void serial_soft_trans_irq(void* parameter);
/* ----------------------- Start implementation -----------------------------*/
BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
eMBParity eParity)
{
rt_device_t dev = RT_NULL;
char uart_name[20];
/**
* set 485 mode receive and transmit control IO
* @note MODBUS_SLAVE_RT_CONTROL_PIN_INDEX need be defined by user
*/
#if defined(RT_MODBUS_SLAVE_USE_CONTROL_PIN)
rt_pin_mode(MODBUS_SLAVE_RT_CONTROL_PIN_INDEX, PIN_MODE_OUTPUT);
#endif
/* set serial name */
rt_snprintf(uart_name,sizeof(uart_name), "uart%d", ucPORT);
dev = rt_device_find(uart_name);
if(dev == RT_NULL)
{
/* can not find uart */
return FALSE;
}
else
{
serial = (struct rt_serial_device*)dev;
}
/* set serial configure parameter */
serial->config.baud_rate = ulBaudRate;
serial->config.stop_bits = STOP_BITS_1;
switch(eParity){
case MB_PAR_NONE: {
serial->config.data_bits = DATA_BITS_8;
serial->config.parity = PARITY_NONE;
break;
}
case MB_PAR_ODD: {
serial->config.data_bits = DATA_BITS_9;
serial->config.parity = PARITY_ODD;
break;
}
case MB_PAR_EVEN: {
serial->config.data_bits = DATA_BITS_9;
serial->config.parity = PARITY_EVEN;
break;
}
}
/* set serial configure */
serial->ops->configure(serial, &(serial->config));
/* open serial device */
if (!rt_device_open(&serial->parent, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX)) {
rt_device_set_rx_indicate(&serial->parent, serial_rx_ind);
} else {
return FALSE;
}
/* software initialize */
rt_event_init(&event_serial, "slave event", RT_IPC_FLAG_PRIO);
rt_thread_init(&thread_serial_soft_trans_irq,
"slave trans",
serial_soft_trans_irq,
RT_NULL,
serial_soft_trans_irq_stack,
sizeof(serial_soft_trans_irq_stack),
10, 5);
rt_thread_startup(&thread_serial_soft_trans_irq);
return TRUE;
}
void vMBPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable)
{
rt_uint32_t recved_event;
if (xRxEnable)
{
/* enable RX interrupt */
serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX);
/* switch 485 to receive mode */
#if defined(RT_MODBUS_SLAVE_USE_CONTROL_PIN)
rt_pin_write(MODBUS_SLAVE_RT_CONTROL_PIN_INDEX, PIN_LOW);
#endif
}
else
{
/* switch 485 to transmit mode */
#if defined(RT_MODBUS_SLAVE_USE_CONTROL_PIN)
rt_pin_write(MODBUS_SLAVE_RT_CONTROL_PIN_INDEX, PIN_HIGH);
#endif
/* disable RX interrupt */
serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_FLAG_INT_RX);
}
if (xTxEnable)
{
/* start serial transmit */
rt_event_send(&event_serial, EVENT_SERIAL_TRANS_START);
}
else
{
/* stop serial transmit */
rt_event_recv(&event_serial, EVENT_SERIAL_TRANS_START,
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, 0,
&recved_event);
}
}
void vMBPortClose(void)
{
serial->parent.close(&(serial->parent));
}
BOOL xMBPortSerialPutByte(CHAR ucByte)
{
serial->parent.write(&(serial->parent), 0, &ucByte, 1);
return TRUE;
}
BOOL xMBPortSerialGetByte(CHAR * pucByte)
{
serial->parent.read(&(serial->parent), 0, pucByte, 1);
return TRUE;
}
/*
* Create an interrupt handler for the transmit buffer empty interrupt
* (or an equivalent) for your target processor. This function should then
* call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that
* a new character can be sent. The protocol stack will then call
* xMBPortSerialPutByte( ) to send the character.
*/
void prvvUARTTxReadyISR(void)
{
pxMBFrameCBTransmitterEmpty();
}
/*
* Create an interrupt handler for the receive interrupt for your target
* processor. This function should then call pxMBFrameCBByteReceived( ). The
* protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
* character.
*/
void prvvUARTRxISR(void)
{
pxMBFrameCBByteReceived();
}
/**
* Software simulation serial transmit IRQ handler.
*
* @param parameter parameter
*/
static void serial_soft_trans_irq(void* parameter) {
rt_uint32_t recved_event;
while (1)
{
/* waiting for serial transmit start */
rt_event_recv(&event_serial, EVENT_SERIAL_TRANS_START, RT_EVENT_FLAG_OR,
RT_WAITING_FOREVER, &recved_event);
/* execute modbus callback */
prvvUARTTxReadyISR();
}
}
/**
* This function is serial receive callback function
*
* @param dev the device of serial
* @param size the data size that receive
*
* @return return RT_EOK
*/
static rt_err_t serial_rx_ind(rt_device_t dev, rt_size_t size) {
while(size--)
prvvUARTRxISR();
return RT_EOK;
}
#endif
#ifdef ADD_XIZI_FEATURES
/* ----------------------- Static variables ---------------------------------*/
/* software simulation serial transmit IRQ handler thread */
static pthread_t thread_serial_soft_trans_irq;
static pthread_t thread_serial_recv_irq;
/* serial event */
static int event_serial;
/* modbus slave serial device */
static int pin_fd = 0;
static int uart_fd = 0;
/* ----------------------- Defines ------------------------------------------*/
/* serial transmit event */
#define EVENT_SERIAL_TRANS_START (1<<0)
#define RTU_RECV_DATA_LENGTH 8
/* ----------------------- static functions ---------------------------------*/
static void prvvUARTTxReadyISR(void);
static void prvvUARTRxISR(CHAR pucByte);
static void *serial_soft_trans_irq(void* parameter);
static void *serial_recv_irq(void* parameter);
/* ----------------------- Start implementation -----------------------------*/
BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
eMBParity eParity)
{
int ret = 0;
uint32_t baud_rate;
uint8_t data_bits, parity;
baud_rate = ulBaudRate;
data_bits = ucDataBits;
/* set serial configure parameter */
switch(eParity){
case MB_PAR_NONE: {
parity = PARITY_NONE;
break;
}
case MB_PAR_ODD: {
parity = PARITY_ODD;
break;
}
case MB_PAR_EVEN: {
parity = PARITY_EVEN;
break;
}
}
pin_fd = PrivOpen(CONNECTION_MODBUS_RTU_PIN_DEV, O_RDWR);
if (pin_fd < 0) {
printf("open %s error\n", CONNECTION_MODBUS_RTU_PIN_DEV);
return FALSE;
}
struct PinParam pin_param;
pin_param.cmd = GPIO_CONFIG_MODE;
pin_param.mode = GPIO_CFG_OUTPUT;
pin_param.pin = CONNECTION_MODBUS_RTU_UART_485_DIR;
struct PrivIoctlCfg ioctl_cfg;
ioctl_cfg.ioctl_driver_type = PIN_TYPE;
ioctl_cfg.args = &pin_param;
PrivIoctl(pin_fd, OPE_CFG, &ioctl_cfg);
uart_fd = PrivOpen(CONNECTION_MODBUS_RTU_UART_DEV, O_RDWR);
if (uart_fd < 0) {
printf("open fd error %d\n", uart_fd);
return FALSE;
}
printf("%s open fd %d baud_rate %d data_bits %d check_mode %d\n",
__func__, uart_fd, baud_rate, data_bits, parity);
struct SerialDataCfg cfg;
cfg.serial_baud_rate = baud_rate;
cfg.serial_data_bits = data_bits;
cfg.serial_stop_bits = STOP_BITS_1;
cfg.serial_buffer_size = 128;
cfg.serial_parity_mode = parity;
cfg.serial_bit_order = 1;
cfg.serial_invert_mode = 1;
#ifdef CONNECTION_MODBUS_RTU_EXTUART
cfg.ext_uart_no = CONNECTION_MODBUS_RTU_UART_DEV_EXT_PORT;
cfg.port_configure = PORT_CFG_INIT;
#endif
cfg.serial_timeout = -1;
cfg.dev_recv_callback = NULL;
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
ioctl_cfg.args = &cfg;
ret = PrivIoctl(uart_fd, OPE_INT, &ioctl_cfg);
if (0 != ret) {
printf("ioctl fd error %d\n", ret);
return FALSE;
}
printf("%s serial init done!\n", __func__);
/* software initialize */
event_serial = PrivEventCreate(LINKLIST_FLAG_PRIO);
pthread_attr_t attr;
attr.schedparam.sched_priority = 21;
attr.stacksize = 1024;
char task_name[] = "slave_trans";
pthread_args_t args;
args.pthread_name = task_name;
PrivTaskCreate(&thread_serial_soft_trans_irq, &attr, &serial_soft_trans_irq, (void *)&args);
PrivTaskStartup(&thread_serial_soft_trans_irq);
attr.schedparam.sched_priority = 22;
attr.stacksize = 2048;
char task2_name[] = "slave_recv";
args.pthread_name = task2_name;
PrivTaskCreate(&thread_serial_recv_irq, &attr, &serial_recv_irq, (void *)&args);
PrivTaskStartup(&thread_serial_recv_irq);
return TRUE;
}
/**
* @description: Set Uart 485 Input
* @return
*/
static void Set485Input(void)
{
PrivTaskDelay(15);
struct PinStat pin_stat;
pin_stat.pin = CONNECTION_MODBUS_RTU_UART_485_DIR;
pin_stat.val = GPIO_LOW;
PrivWrite(pin_fd, &pin_stat, 1);
}
/**
* @description: Set Uart 485 Output
* @return
*/
static void Set485Output(void)
{
struct PinStat pin_stat;
pin_stat.pin = CONNECTION_MODBUS_RTU_UART_485_DIR;
pin_stat.val = GPIO_HIGH;
PrivWrite(pin_fd, &pin_stat, 1);
PrivTaskDelay(20);
}
void vMBPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable)
{
unsigned int recved_event;
if (xRxEnable) {
/* switch 485 to receive mode */
Set485Input();
} else {
/* switch 485 to transmit mode */
Set485Output();
}
if (xTxEnable) {
/* start serial transmit */
PrivEvenTrigger(event_serial, EVENT_SERIAL_TRANS_START);
} else {
/* stop serial transmit */
PrivEventProcess(event_serial, EVENT_SERIAL_TRANS_START, EVENT_OR | EVENT_AUTOCLEAN, 0, &recved_event);
}
}
void vMBPortClose(void)
{
}
BOOL xMBPortSerialPutByte(CHAR ucByte)
{
PrivWrite(uart_fd, &ucByte, 1);
return TRUE;
}
BOOL xMBPortSerialGetByte(CHAR * pucByte)
{
PrivRead(uart_fd, pucByte, 1);
PrivTaskDelay(30);
return TRUE;
}
/*
* Create an interrupt handler for the transmit buffer empty interrupt
* (or an equivalent) for your target processor. This function should then
* call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that
* a new character can be sent. The protocol stack will then call
* xMBPortSerialPutByte( ) to send the character.
*/
void prvvUARTTxReadyISR(void)
{
pxMBFrameCBTransmitterEmpty();
}
/*
* Create an interrupt handler for the receive interrupt for your target
* processor. This function should then call pxMBFrameCBByteReceived( ). The
* protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
* character.
*/
void prvvUARTRxISR(CHAR pucByte)
{
pxMBFrameCBByteReceived(pucByte);
}
/**
* Software simulation serial transmit IRQ handler.
*
* @param parameter parameter
*/
static void *serial_soft_trans_irq(void* parameter) {
unsigned int recved_event;
while (1) {
/* waiting for serial transmit start */
if (0 == PrivEventProcess(event_serial, EVENT_SERIAL_TRANS_START, EVENT_OR, 0, &recved_event)) {
/* execute modbus callback */
prvvUARTTxReadyISR();
}
}
}
/**
* Software simulation serial receive data IRQ handler.
*
* @param parameter parameter
*/
static void *serial_recv_irq(void* parameter) {
int i;
int data_size = 0;
int data_recv_size = 0;
char recv_data[RTU_RECV_DATA_LENGTH] = {0};
while (1) {
while (data_size < RTU_RECV_DATA_LENGTH) {
data_recv_size = PrivRead(uart_fd, recv_data + data_size, RTU_RECV_DATA_LENGTH - data_size);
data_size += data_recv_size;
}
/* execute modbus recv callback */
for (i = 0; i < RTU_RECV_DATA_LENGTH; i ++) {
prvvUARTRxISR(recv_data[i]);
}
data_size = 0;
data_recv_size = 0;
}
}
#endif

View File

@ -0,0 +1,515 @@
/*
* FreeModbus Libary: RT-Thread Port
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id: portserial_m.c,v 1.60 2013/08/13 15:07:05 Armink add Master Functions $
*/
/**
* @file portserial_m.c
* @brief support freemodbus port for XiUOS
* @version 3.0
* @author AIIT XUOS Lab
* @date 2023-10-12
*/
/*************************************************
File name: portserial_m.c
Description: support freemodbus port for XiUOS
Others:
History:
1. Date: 2023-10-12
Author: AIIT XUOS Lab
Modification:
1support XiUOS serial for master.
*************************************************/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
#ifdef ADD_RTTHREAD_FEATURES
#include "rtdevice.h"
#include "board.h"
#endif
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
#ifdef ADD_RTTHREAD_FEATURES
/* ----------------------- Static variables ---------------------------------*/
/* software simulation serial transmit IRQ handler thread stack */
#ifdef rt_align
rt_align(RT_ALIGN_SIZE)
#else
ALIGN(RT_ALIGN_SIZE)
#endif
static rt_uint8_t serial_soft_trans_irq_stack[512];
/* software simulation serial transmit IRQ handler thread */
static struct rt_thread thread_serial_soft_trans_irq;
/* serial event */
static struct rt_event event_serial;
/* modbus master serial device */
static struct rt_serial_device *serial;
/* ----------------------- Defines ------------------------------------------*/
/* serial transmit event */
#define EVENT_SERIAL_TRANS_START (1<<0)
/* ----------------------- static functions ---------------------------------*/
static void prvvUARTTxReadyISR(void);
static void prvvUARTRxISR(void);
static rt_err_t serial_rx_ind(rt_device_t dev, rt_size_t size);
static void serial_soft_trans_irq(void* parameter);
/* ----------------------- Start implementation -----------------------------*/
BOOL xMBMasterPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
eMBParity eParity)
{
rt_device_t dev = RT_NULL;
char uart_name[20];
/**
* set 485 mode receive and transmit control IO
* @note MODBUS_MASTER_RT_CONTROL_PIN_INDEX need be defined by user
*/
#if defined(RT_MODBUS_MASTER_USE_CONTROL_PIN)
rt_pin_mode(MODBUS_MASTER_RT_CONTROL_PIN_INDEX, PIN_MODE_OUTPUT);
#endif
/* set serial name */
rt_snprintf(uart_name,sizeof(uart_name), "uart%d", ucPORT);
dev = rt_device_find(uart_name);
if(dev == RT_NULL)
{
/* can not find uart */
return FALSE;
}
else
{
serial = (struct rt_serial_device*)dev;
}
/* set serial configure parameter */
serial->config.baud_rate = ulBaudRate;
serial->config.stop_bits = STOP_BITS_1;
switch(eParity){
case MB_PAR_NONE: {
serial->config.data_bits = DATA_BITS_8;
serial->config.parity = PARITY_NONE;
break;
}
case MB_PAR_ODD: {
serial->config.data_bits = DATA_BITS_9;
serial->config.parity = PARITY_ODD;
break;
}
case MB_PAR_EVEN: {
serial->config.data_bits = DATA_BITS_9;
serial->config.parity = PARITY_EVEN;
break;
}
}
/* set serial configure */
serial->ops->configure(serial, &(serial->config));
/* open serial device */
if (!rt_device_open(&serial->parent, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX)) {
rt_device_set_rx_indicate(&serial->parent, serial_rx_ind);
} else {
return FALSE;
}
/* software initialize */
rt_event_init(&event_serial, "master event", RT_IPC_FLAG_PRIO);
rt_thread_init(&thread_serial_soft_trans_irq,
"master trans",
serial_soft_trans_irq,
RT_NULL,
serial_soft_trans_irq_stack,
sizeof(serial_soft_trans_irq_stack),
10, 5);
rt_thread_startup(&thread_serial_soft_trans_irq);
return TRUE;
}
void vMBMasterPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable)
{
rt_uint32_t recved_event;
if (xRxEnable)
{
/* enable RX interrupt */
serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX);
/* switch 485 to receive mode */
#if defined(RT_MODBUS_MASTER_USE_CONTROL_PIN)
rt_pin_write(MODBUS_MASTER_RT_CONTROL_PIN_INDEX, PIN_LOW);
#endif
}
else
{
/* switch 485 to transmit mode */
#if defined(RT_MODBUS_MASTER_USE_CONTROL_PIN)
rt_pin_write(MODBUS_MASTER_RT_CONTROL_PIN_INDEX, PIN_HIGH);
#endif
/* disable RX interrupt */
serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_FLAG_INT_RX);
}
if (xTxEnable)
{
/* start serial transmit */
rt_event_send(&event_serial, EVENT_SERIAL_TRANS_START);
}
else
{
/* stop serial transmit */
rt_event_recv(&event_serial, EVENT_SERIAL_TRANS_START,
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, 0,
&recved_event);
}
}
void vMBMasterPortClose(void)
{
serial->parent.close(&(serial->parent));
}
BOOL xMBMasterPortSerialPutByte(CHAR ucByte)
{
serial->parent.write(&(serial->parent), 0, &ucByte, 1);
return TRUE;
}
BOOL xMBMasterPortSerialGetByte(CHAR * pucByte)
{
serial->parent.read(&(serial->parent), 0, pucByte, 1);
return TRUE;
}
/*
* Create an interrupt handler for the transmit buffer empty interrupt
* (or an equivalent) for your target processor. This function should then
* call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that
* a new character can be sent. The protocol stack will then call
* xMBPortSerialPutByte( ) to send the character.
*/
void prvvUARTTxReadyISR(void)
{
pxMBMasterFrameCBTransmitterEmpty();
}
/*
* Create an interrupt handler for the receive interrupt for your target
* processor. This function should then call pxMBFrameCBByteReceived( ). The
* protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
* character.
*/
void prvvUARTRxISR(void)
{
pxMBMasterFrameCBByteReceived();
}
/**
* Software simulation serial transmit IRQ handler.
*
* @param parameter parameter
*/
static void serial_soft_trans_irq(void* parameter) {
rt_uint32_t recved_event;
while (1)
{
/* waiting for serial transmit start */
rt_event_recv(&event_serial, EVENT_SERIAL_TRANS_START, RT_EVENT_FLAG_OR,
RT_WAITING_FOREVER, &recved_event);
/* execute modbus callback */
prvvUARTTxReadyISR();
}
}
/**
* This function is serial receive callback function
*
* @param dev the device of serial
* @param size the data size that receive
*
* @return return RT_EOK
*/
static rt_err_t serial_rx_ind(rt_device_t dev, rt_size_t size) {
prvvUARTRxISR();
return RT_EOK;
}
#endif
#ifdef ADD_XIZI_FEATURES
/* ----------------------- Static variables ---------------------------------*/
/* software simulation serial transmit IRQ handler thread */
static pthread_t thread_serial_soft_trans_irq;
static pthread_t thread_serial_recv_irq;
/* serial event */
static int event_serial;
/* modbus master serial device */
static int pin_fd = 0;
static int uart_fd = 0;
/* ----------------------- Defines ------------------------------------------*/
/* serial transmit event */
#define EVENT_SERIAL_TRANS_START (1<<0)
#define RTU_RECV_DATA_LENGTH 8
/* ----------------------- static functions ---------------------------------*/
static void prvvUARTTxReadyISR(void);
static void prvvUARTRxISR(CHAR pucByte);
static void *serial_soft_trans_irq(void* parameter);
static void *serial_recv_irq(void* parameter);
/* ----------------------- Start implementation -----------------------------*/
BOOL xMBMasterPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
eMBParity eParity)
{
int ret = 0;
uint32_t baud_rate;
uint8_t data_bits, parity;
baud_rate = ulBaudRate;
data_bits = ucDataBits;
/* set serial configure parameter */
switch(eParity){
case MB_PAR_NONE: {
parity = PARITY_NONE;
break;
}
case MB_PAR_ODD: {
parity = PARITY_ODD;
break;
}
case MB_PAR_EVEN: {
parity = PARITY_EVEN;
break;
}
}
pin_fd = PrivOpen(CONNECTION_MODBUS_RTU_PIN_DEV, O_RDWR);
if (pin_fd < 0) {
printf("open %s error\n", CONNECTION_MODBUS_RTU_PIN_DEV);
return FALSE;
}
struct PinParam pin_param;
pin_param.cmd = GPIO_CONFIG_MODE;
pin_param.mode = GPIO_CFG_OUTPUT;
pin_param.pin = CONNECTION_MODBUS_RTU_UART_485_DIR;
struct PrivIoctlCfg ioctl_cfg;
ioctl_cfg.ioctl_driver_type = PIN_TYPE;
ioctl_cfg.args = &pin_param;
PrivIoctl(pin_fd, OPE_CFG, &ioctl_cfg);
uart_fd = PrivOpen(CONNECTION_MODBUS_RTU_UART_DEV, O_RDWR);
if (uart_fd < 0) {
printf("open fd error %d\n", uart_fd);
return FALSE;
}
printf("%s open fd %d baud_rate %d data_bits %d check_mode %d\n",
__func__, uart_fd, baud_rate, data_bits, parity);
struct SerialDataCfg cfg;
cfg.serial_baud_rate = baud_rate;
cfg.serial_data_bits = data_bits;
cfg.serial_stop_bits = STOP_BITS_1;
cfg.serial_buffer_size = 128;
cfg.serial_parity_mode = parity;
cfg.serial_bit_order = 1;
cfg.serial_invert_mode = 1;
#ifdef CONNECTION_MODBUS_RTU_EXTUART
cfg.ext_uart_no = 0;
cfg.port_configure = PORT_CFG_INIT;
#endif
cfg.serial_timeout = -1;
cfg.dev_recv_callback = NULL;
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
ioctl_cfg.args = &cfg;
ret = PrivIoctl(uart_fd, OPE_INT, &ioctl_cfg);
if (0 != ret) {
printf("ioctl fd error %d\n", ret);
return FALSE;
}
printf("%s serial init done!\n", __func__);
/* software initialize */
event_serial = PrivEventCreate(LINKLIST_FLAG_PRIO);
pthread_attr_t attr;
attr.schedparam.sched_priority = 21;
attr.stacksize = 2048;
char task1_name[] = "master_trans";
pthread_args_t args;
args.pthread_name = task1_name;
PrivTaskCreate(&thread_serial_soft_trans_irq, &attr, &serial_soft_trans_irq, (void *)&args);
PrivTaskStartup(&thread_serial_soft_trans_irq);
attr.schedparam.sched_priority = 22;
attr.stacksize = 2048;
char task2_name[] = "master_recv";
args.pthread_name = task2_name;
PrivTaskCreate(&thread_serial_recv_irq, &attr, &serial_recv_irq, (void *)&args);
PrivTaskStartup(&thread_serial_recv_irq);
return TRUE;
}
/**
* @description: Set Uart 485 Input
* @return
*/
static void Set485Input(void)
{
PrivTaskDelay(15);
struct PinStat pin_stat;
pin_stat.pin = CONNECTION_MODBUS_RTU_UART_485_DIR;
pin_stat.val = GPIO_LOW;
PrivWrite(pin_fd, &pin_stat, 1);
}
/**
* @description: Set Uart 485 Output
* @return
*/
static void Set485Output(void)
{
struct PinStat pin_stat;
pin_stat.pin = CONNECTION_MODBUS_RTU_UART_485_DIR;
pin_stat.val = GPIO_HIGH;
PrivWrite(pin_fd, &pin_stat, 1);
PrivTaskDelay(20);
}
void vMBMasterPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable)
{
unsigned int recved_event;
if (xRxEnable) {
/* switch 485 to receive mode */
Set485Input();
} else {
/* switch 485 to transmit mode */
Set485Output();
}
if (xTxEnable) {
/* start serial transmit */
PrivEvenTrigger(event_serial, EVENT_SERIAL_TRANS_START);
} else {
/* stop serial transmit */
PrivEventProcess(event_serial, EVENT_SERIAL_TRANS_START, EVENT_OR | EVENT_AUTOCLEAN, 0, &recved_event);
}
}
void vMBMasterPortClose(void)
{
}
BOOL xMBMasterPortSerialPutByte(CHAR ucByte)
{
PrivWrite(uart_fd, &ucByte, 1);
return TRUE;
}
BOOL xMBMasterPortSerialGetByte(CHAR * pucByte)
{
PrivRead(uart_fd, pucByte, 1);
PrivTaskDelay(30);
return TRUE;
}
/*
* Create an interrupt handler for the transmit buffer empty interrupt
* (or an equivalent) for your target processor. This function should then
* call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that
* a new character can be sent. The protocol stack will then call
* xMBPortSerialPutByte( ) to send the character.
*/
void prvvUARTTxReadyISR(void)
{
pxMBMasterFrameCBTransmitterEmpty();
}
/*
* Create an interrupt handler for the receive interrupt for your target
* processor. This function should then call pxMBFrameCBByteReceived( ). The
* protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
* character.
*/
void prvvUARTRxISR(CHAR pucByte)
{
pxMBMasterFrameCBByteReceived(pucByte);
}
/**
* Software simulation serial transmit IRQ handler.
*
* @param parameter parameter
*/
static void *serial_soft_trans_irq(void* parameter) {
unsigned int recved_event;
while (1) {
/* waiting for serial transmit start */
if (0 == PrivEventProcess(event_serial, EVENT_SERIAL_TRANS_START, EVENT_OR, 0, &recved_event)) {
/* execute modbus callback */
prvvUARTTxReadyISR();
}
}
}
/**
* Software simulation serial receive data IRQ handler.
*
* @param parameter parameter
*/
static void *serial_recv_irq(void* parameter) {
int i;
int data_size = 0;
int data_recv_size = 0;
char recv_data[RTU_RECV_DATA_LENGTH] = {0};
while (1) {
while (data_size < RTU_RECV_DATA_LENGTH) {
data_recv_size = PrivRead(uart_fd, recv_data + data_size, RTU_RECV_DATA_LENGTH - data_size);
data_size += data_recv_size;
}
/* execute modbus recv callback */
for (i = 0; i < RTU_RECV_DATA_LENGTH; i ++) {
prvvUARTRxISR(recv_data[i]);
}
data_size = 0;
data_recv_size = 0;
}
}
#endif
#endif

View File

@ -0,0 +1,134 @@
/*
* FreeModbus Libary: RT-Thread Port
* Copyright (C) 2019 flybreak <guozhanxin@rt-thread.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id: portserial.c,v 1.60 2019/07/11 17:04:32 flybreak $
*/
#include "port.h"
#ifdef PKG_MODBUS_SLAVE_TCP
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
#include "tcpserver.h"
/* ----------------------- Defines -----------------------------------------*/
#define MB_TCP_DEFAULT_PORT 502
#define MB_TCP_BUF_SIZE ( 256 + 7 )
/* ----------------------- Static variables ---------------------------------*/
static tcpclient_t mb_client;
static UCHAR prvvTCPBuf[MB_TCP_BUF_SIZE];
static USHORT prvvTCPLength;
static void tcpserver_event_notify(tcpclient_t client, rt_uint8_t event)
{
static rt_tick_t recv_tick = 0;
switch (event)
{
case TCPSERVER_EVENT_CONNECT:
if (mb_client == RT_NULL)
{
mb_client = client;
}
else
{
if(rt_tick_get() - recv_tick > 30 * RT_TICK_PER_SECOND) /* set timeout as 30s */
{
tcpserver_close(mb_client);
mb_client = client;
recv_tick = rt_tick_get();
}
else
{
tcpserver_close(client);
rt_kprintf("Multi-host is not supported, please disconnect the current host first!\n");
}
}
break;
case TCPSERVER_EVENT_RECV:
if( mb_client == client)
{
recv_tick = rt_tick_get();
prvvTCPLength = tcpserver_recv(mb_client, &prvvTCPBuf, MB_TCP_BUF_SIZE, 100);
if (prvvTCPLength)
{
xMBPortEventPost(EV_FRAME_RECEIVED);
}
}
break;
case TCPSERVER_EVENT_DISCONNECT:
if (mb_client == client)
mb_client = RT_NULL;
break;
default:
break;
}
}
BOOL
xMBTCPPortInit(USHORT usTCPPort)
{
struct tcpserver *serv;
if (usTCPPort == 0)
usTCPPort = MB_TCP_DEFAULT_PORT;
serv = tcpserver_create(0, usTCPPort);
tcpserver_set_notify_callback(serv, tcpserver_event_notify);
return TRUE;
}
void
vMBTCPPortClose(void)
{
tcpserver_destroy(mb_client->server);
}
void
vMBTCPPortDisable(void)
{
tcpserver_close(mb_client);
}
BOOL
xMBTCPPortGetRequest(UCHAR **ppucMBTCPFrame, USHORT *usTCPLength)
{
*ppucMBTCPFrame = &prvvTCPBuf[0];
*usTCPLength = prvvTCPLength;
return TRUE;
}
BOOL
xMBTCPPortSendResponse(const UCHAR *pucMBTCPFrame, USHORT usTCPLength)
{
rt_int16_t ret;
BOOL bFrameSent = FALSE;
if (mb_client)
{
ret = tcpserver_send(mb_client, (void *)pucMBTCPFrame, usTCPLength, 0);
if (ret == usTCPLength)
bFrameSent = TRUE;
}
return bFrameSent;
}
#endif

View File

@ -0,0 +1,141 @@
/*
* FreeModbus Libary: RT-Thread Port
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id: porttimer.c,v 1.60 2013/08/13 15:07:05 Armink $
*/
/**
* @file porttimer.c
* @brief support freemodbus port for XiUOS
* @version 3.0
* @author AIIT XUOS Lab
* @date 2023-10-12
*/
/*************************************************
File name: porttimer.c
Description: support freemodbus port for XiUOS
Others:
History:
1. Date: 2023-10-12
Author: AIIT XUOS Lab
Modification:
1support XiUOS timer for slave.
*************************************************/
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
#ifdef ADD_RTTHREAD_FEATURES
/* ----------------------- static functions ---------------------------------*/
static struct rt_timer timer;
static void prvvTIMERExpiredISR(void);
static void timer_timeout_ind(void* parameter);
/* ----------------------- Start implementation -----------------------------*/
BOOL xMBPortTimersInit(USHORT usTim1Timerout50us)
{
rt_timer_init(&timer, "slave timer",
timer_timeout_ind, /* bind timeout callback function */
RT_NULL,
(50 * usTim1Timerout50us) / (1000 * 1000 / RT_TICK_PER_SECOND) + 1,
RT_TIMER_FLAG_ONE_SHOT); /* one shot */
return TRUE;
}
void vMBPortTimersEnable()
{
rt_timer_start(&timer);
}
void vMBPortTimersDisable()
{
rt_timer_stop(&timer);
}
void prvvTIMERExpiredISR(void)
{
(void) pxMBPortCBTimerExpired();
}
static void timer_timeout_ind(void* parameter)
{
prvvTIMERExpiredISR();
}
#endif
#ifdef ADD_XIZI_FEATURES
/* ----------------------- static functions ---------------------------------*/
static timer_t timer_id;
static void prvvTIMERExpiredISR(void);
static void timer_timeout_ind(union sigval sig_val);
/* ----------------------- Start implementation -----------------------------*/
BOOL xMBPortTimersInit(USHORT usTim1Timerout50us)
{
int ret = 0;
int timer_flags;
static int count = 0;
struct sigevent evp;
memset(&evp, 0, sizeof(struct sigevent));
timer_flags = TIMER_TRIGGER_ONCE;
count++;
evp.sigev_notify = SIGEV_THREAD;
evp.sigev_notify_function = timer_timeout_ind;
evp.sigev_notify_attributes = &timer_flags;
ret = PrivTimerCreate(count, &evp, &timer_id);
if (ret < 0) {
printf("%s create timer failed ret %d\n", __func__, ret);
return FALSE;
}
UserTimerModify(timer_id, (50 * usTim1Timerout50us) / (1000 * 1000 / TICK_PER_SECOND) + 1);
return TRUE;
}
void vMBPortTimersEnable()
{
PrivTimerStartRun(timer_id);
}
void vMBPortTimersDisable()
{
PrivTimerQuitRun(timer_id);
}
void prvvTIMERExpiredISR(void)
{
(void) pxMBPortCBTimerExpired();
}
static void timer_timeout_ind(union sigval sig_val)
{
prvvTIMERExpiredISR();
}
#endif

View File

@ -0,0 +1,222 @@
/*
* FreeModbus Libary: RT-Thread Port
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id: porttimer_m.c,v 1.60 2013/08/13 15:07:05 Armink add Master Functions$
*/
/**
* @file porttimer_m.c
* @brief support freemodbus port for XiUOS
* @version 3.0
* @author AIIT XUOS Lab
* @date 2023-10-12
*/
/*************************************************
File name: porttimer_m.c
Description: support freemodbus port for XiUOS
Others:
History:
1. Date: 2023-10-12
Author: AIIT XUOS Lab
Modification:
1support XiUOS timer for master.
*************************************************/
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mb_m.h"
#include "mbport.h"
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
#ifdef ADD_RTTHREAD_FEATURES
/* ----------------------- Variables ----------------------------------------*/
static USHORT usT35TimeOut50us;
static struct rt_timer timer;
static void prvvTIMERExpiredISR(void);
static void timer_timeout_ind(void* parameter);
/* ----------------------- static functions ---------------------------------*/
static void prvvTIMERExpiredISR(void);
/* ----------------------- Start implementation -----------------------------*/
BOOL xMBMasterPortTimersInit(USHORT usTimeOut50us)
{
/* backup T35 ticks */
usT35TimeOut50us = usTimeOut50us;
rt_timer_init(&timer, "master timer",
timer_timeout_ind, /* bind timeout callback function */
RT_NULL,
(50 * usT35TimeOut50us) / (1000 * 1000 / RT_TICK_PER_SECOND) + 1,
RT_TIMER_FLAG_ONE_SHOT); /* one shot */
return TRUE;
}
void vMBMasterPortTimersT35Enable()
{
rt_tick_t timer_tick = (50 * usT35TimeOut50us)
/ (1000 * 1000 / RT_TICK_PER_SECOND) + 1;
/* Set current timer mode, don't change it.*/
vMBMasterSetCurTimerMode(MB_TMODE_T35);
rt_timer_control(&timer, RT_TIMER_CTRL_SET_TIME, &timer_tick);
rt_timer_start(&timer);
}
void vMBMasterPortTimersConvertDelayEnable()
{
rt_tick_t timer_tick = MB_MASTER_DELAY_MS_CONVERT * RT_TICK_PER_SECOND / 1000;
/* Set current timer mode, don't change it.*/
vMBMasterSetCurTimerMode(MB_TMODE_CONVERT_DELAY);
rt_timer_control(&timer, RT_TIMER_CTRL_SET_TIME, &timer_tick);
rt_timer_start(&timer);
}
void vMBMasterPortTimersRespondTimeoutEnable()
{
rt_tick_t timer_tick = MB_MASTER_TIMEOUT_MS_RESPOND * RT_TICK_PER_SECOND / 1000;
/* Set current timer mode, don't change it.*/
vMBMasterSetCurTimerMode(MB_TMODE_RESPOND_TIMEOUT);
rt_timer_control(&timer, RT_TIMER_CTRL_SET_TIME, &timer_tick);
rt_timer_start(&timer);
}
void vMBMasterPortTimersDisable()
{
rt_timer_stop(&timer);
}
void prvvTIMERExpiredISR(void)
{
(void) pxMBMasterPortCBTimerExpired();
}
static void timer_timeout_ind(void* parameter)
{
prvvTIMERExpiredISR();
}
#endif
#ifdef ADD_XIZI_FEATURES
/* ----------------------- Variables ----------------------------------------*/
static USHORT usT35TimeOut50us;
static timer_t timer_id;
static void prvvTIMERExpiredISR(void);
static void timer_timeout_ind(union sigval sig_val);
/* ----------------------- static functions ---------------------------------*/
static void prvvTIMERExpiredISR(void);
/* ----------------------- Start implementation -----------------------------*/
BOOL xMBMasterPortTimersInit(USHORT usTimeOut50us)
{
/* backup T35 ticks */
usT35TimeOut50us = usTimeOut50us;
int ret = 0;
int timer_flags;
static int count = 0;
struct sigevent evp;
memset(&evp, 0, sizeof(struct sigevent));
timer_flags = TIMER_TRIGGER_ONCE;
count++;
evp.sigev_notify = SIGEV_THREAD;
evp.sigev_notify_function = timer_timeout_ind;
evp.sigev_notify_attributes = &timer_flags;
ret = PrivTimerCreate(count, &evp, &timer_id);
if (ret < 0) {
printf("%s create timer failed ret %d\n", __func__, ret);
return FALSE;
}
return TRUE;
}
void vMBMasterPortTimersT35Enable()
{
int timer_tick = (50 * usT35TimeOut50us)
/ (1000 * 1000 / TICK_PER_SECOND) + 1;
/* Set current timer mode, don't change it.*/
vMBMasterSetCurTimerMode(MB_TMODE_T35);
UserTimerModify(timer_id, timer_tick);
UserTimerStartRun(timer_id);
}
void vMBMasterPortTimersConvertDelayEnable()
{
int timer_tick = MB_MASTER_DELAY_MS_CONVERT * TICK_PER_SECOND / 1000;
/* Set current timer mode, don't change it.*/
vMBMasterSetCurTimerMode(MB_TMODE_CONVERT_DELAY);
UserTimerModify(timer_id, timer_tick);
UserTimerStartRun(timer_id);
}
void vMBMasterPortTimersRespondTimeoutEnable()
{
int timer_tick = MB_MASTER_TIMEOUT_MS_RESPOND * TICK_PER_SECOND / 1000;
/* Set current timer mode, don't change it.*/
vMBMasterSetCurTimerMode(MB_TMODE_RESPOND_TIMEOUT);
UserTimerModify(timer_id, timer_tick);
UserTimerStartRun(timer_id);
}
void vMBMasterPortTimersDisable()
{
PrivTimerQuitRun(timer_id);
}
void prvvTIMERExpiredISR(void)
{
(void) pxMBMasterPortCBTimerExpired();
}
static void timer_timeout_ind(union sigval sig_val)
{
prvvTIMERExpiredISR();
}
#endif
#endif

View File

@ -0,0 +1,286 @@
/*
* FreeModbus Libary: user callback functions and buffer define in slave mode
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id: user_mb_app.c,v 1.60 2013/11/23 11:49:05 Armink $
*/
#include "user_mb_app.h"
/*------------------------Slave mode use these variables----------------------*/
//Slave mode:DiscreteInputs variables
USHORT usSDiscInStart = S_DISCRETE_INPUT_START;
#if S_DISCRETE_INPUT_NDISCRETES%8
UCHAR ucSDiscInBuf[S_DISCRETE_INPUT_NDISCRETES/8+1];
#else
UCHAR ucSDiscInBuf[S_DISCRETE_INPUT_NDISCRETES/8] ;
#endif
//Slave mode:Coils variables
USHORT usSCoilStart = S_COIL_START;
#if S_COIL_NCOILS%8
UCHAR ucSCoilBuf[S_COIL_NCOILS/8+1] ;
#else
UCHAR ucSCoilBuf[S_COIL_NCOILS/8] ;
#endif
//Slave mode:InputRegister variables
USHORT usSRegInStart = S_REG_INPUT_START;
USHORT usSRegInBuf[S_REG_INPUT_NREGS] ;
//Slave mode:HoldingRegister variables
USHORT usSRegHoldStart = S_REG_HOLDING_START;
USHORT usSRegHoldBuf[S_REG_HOLDING_NREGS] ;
/**
* Modbus slave input register callback function.
*
* @param pucRegBuffer input register buffer
* @param usAddress input register address
* @param usNRegs input register number
*
* @return result
*/
eMBErrorCode eMBRegInputCB(UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
{
eMBErrorCode eStatus = MB_ENOERR;
USHORT iRegIndex;
USHORT * pusRegInputBuf;
USHORT REG_INPUT_START;
USHORT REG_INPUT_NREGS;
USHORT usRegInStart;
pusRegInputBuf = usSRegInBuf;
REG_INPUT_START = S_REG_INPUT_START;
REG_INPUT_NREGS = S_REG_INPUT_NREGS;
usRegInStart = usSRegInStart;
/* it already plus one in modbus function method. */
usAddress--;
if ((usAddress >= REG_INPUT_START)
&& (usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS))
{
iRegIndex = usAddress - usRegInStart;
while (usNRegs > 0)
{
*pucRegBuffer++ = (UCHAR) (pusRegInputBuf[iRegIndex] >> 8);
*pucRegBuffer++ = (UCHAR) (pusRegInputBuf[iRegIndex] & 0xFF);
iRegIndex++;
usNRegs--;
}
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}
/**
* Modbus slave holding register callback function.
*
* @param pucRegBuffer holding register buffer
* @param usAddress holding register address
* @param usNRegs holding register number
* @param eMode read or write
*
* @return result
*/
eMBErrorCode eMBRegHoldingCB(UCHAR * pucRegBuffer, USHORT usAddress,
USHORT usNRegs, eMBRegisterMode eMode)
{
eMBErrorCode eStatus = MB_ENOERR;
USHORT iRegIndex;
USHORT * pusRegHoldingBuf;
USHORT REG_HOLDING_START;
USHORT REG_HOLDING_NREGS;
USHORT usRegHoldStart;
pusRegHoldingBuf = usSRegHoldBuf;
REG_HOLDING_START = S_REG_HOLDING_START;
REG_HOLDING_NREGS = S_REG_HOLDING_NREGS;
usRegHoldStart = usSRegHoldStart;
/* it already plus one in modbus function method. */
usAddress--;
if ((usAddress >= REG_HOLDING_START)
&& (usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS))
{
iRegIndex = usAddress - usRegHoldStart;
switch (eMode)
{
/* read current register values from the protocol stack. */
case MB_REG_READ:
while (usNRegs > 0)
{
*pucRegBuffer++ = (UCHAR) (pusRegHoldingBuf[iRegIndex] >> 8);
*pucRegBuffer++ = (UCHAR) (pusRegHoldingBuf[iRegIndex] & 0xFF);
iRegIndex++;
usNRegs--;
}
break;
/* write current register values with new values from the protocol stack. */
case MB_REG_WRITE:
while (usNRegs > 0)
{
pusRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
pusRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
iRegIndex++;
usNRegs--;
}
break;
}
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}
/**
* Modbus slave coils callback function.
*
* @param pucRegBuffer coils buffer
* @param usAddress coils address
* @param usNCoils coils number
* @param eMode read or write
*
* @return result
*/
eMBErrorCode eMBRegCoilsCB(UCHAR * pucRegBuffer, USHORT usAddress,
USHORT usNCoils, eMBRegisterMode eMode)
{
eMBErrorCode eStatus = MB_ENOERR;
USHORT iRegIndex , iRegBitIndex , iNReg;
UCHAR * pucCoilBuf;
USHORT COIL_START;
USHORT COIL_NCOILS;
USHORT usCoilStart;
iNReg = usNCoils / 8 + 1;
pucCoilBuf = ucSCoilBuf;
COIL_START = S_COIL_START;
COIL_NCOILS = S_COIL_NCOILS;
usCoilStart = usSCoilStart;
/* it already plus one in modbus function method. */
usAddress--;
if( ( usAddress >= COIL_START ) &&
( usAddress + usNCoils <= COIL_START + COIL_NCOILS ) )
{
iRegIndex = (USHORT) (usAddress - usCoilStart) / 8;
iRegBitIndex = (USHORT) (usAddress - usCoilStart) % 8;
switch ( eMode )
{
/* read current coil values from the protocol stack. */
case MB_REG_READ:
while (iNReg > 0)
{
*pucRegBuffer++ = xMBUtilGetBits(&pucCoilBuf[iRegIndex++],
iRegBitIndex, 8);
iNReg--;
}
pucRegBuffer--;
/* last coils */
usNCoils = usNCoils % 8;
/* filling zero to high bit */
*pucRegBuffer = *pucRegBuffer << (8 - usNCoils);
*pucRegBuffer = *pucRegBuffer >> (8 - usNCoils);
break;
/* write current coil values with new values from the protocol stack. */
case MB_REG_WRITE:
while (iNReg > 1)
{
xMBUtilSetBits(&pucCoilBuf[iRegIndex++], iRegBitIndex, 8,
*pucRegBuffer++);
iNReg--;
}
/* last coils */
usNCoils = usNCoils % 8;
/* xMBUtilSetBits has bug when ucNBits is zero */
if (usNCoils != 0)
{
xMBUtilSetBits(&pucCoilBuf[iRegIndex++], iRegBitIndex, usNCoils,
*pucRegBuffer++);
}
break;
}
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}
/**
* Modbus slave discrete callback function.
*
* @param pucRegBuffer discrete buffer
* @param usAddress discrete address
* @param usNDiscrete discrete number
*
* @return result
*/
eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
eMBErrorCode eStatus = MB_ENOERR;
USHORT iRegIndex , iRegBitIndex , iNReg;
UCHAR * pucDiscreteInputBuf;
USHORT DISCRETE_INPUT_START;
USHORT DISCRETE_INPUT_NDISCRETES;
USHORT usDiscreteInputStart;
iNReg = usNDiscrete / 8 + 1;
pucDiscreteInputBuf = ucSDiscInBuf;
DISCRETE_INPUT_START = S_DISCRETE_INPUT_START;
DISCRETE_INPUT_NDISCRETES = S_DISCRETE_INPUT_NDISCRETES;
usDiscreteInputStart = usSDiscInStart;
/* it already plus one in modbus function method. */
usAddress--;
if ((usAddress >= DISCRETE_INPUT_START)
&& (usAddress + usNDiscrete <= DISCRETE_INPUT_START + DISCRETE_INPUT_NDISCRETES))
{
iRegIndex = (USHORT) (usAddress - usDiscreteInputStart) / 8;
iRegBitIndex = (USHORT) (usAddress - usDiscreteInputStart) % 8;
while (iNReg > 0)
{
*pucRegBuffer++ = xMBUtilGetBits(&pucDiscreteInputBuf[iRegIndex++],
iRegBitIndex, 8);
iNReg--;
}
pucRegBuffer--;
/* last discrete */
usNDiscrete = usNDiscrete % 8;
/* filling zero to high bit */
*pucRegBuffer = *pucRegBuffer << (8 - usNDiscrete);
*pucRegBuffer = *pucRegBuffer >> (8 - usNDiscrete);
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}

View File

@ -0,0 +1,108 @@
/**
* @file user_mb_app.h
* @brief support freemodbus port for XiUOS
* @version 3.0
* @author AIIT XUOS Lab
* @date 2023-10-12
*/
/*************************************************
File name: user_mb_app.h
Description: support freemodbus port for XiUOS
Others:
History:
1. Date: 2023-10-12
Author: AIIT XUOS Lab
Modification:
1support XiUOS for Defines.
*************************************************/
#ifndef USER_APP
#define USER_APP
#include <transform.h>
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mb_m.h"
#include "mbconfig.h"
#include "mbframe.h"
#include "mbutils.h"
#ifdef ADD_RTTHREAD_FEATURES
/* -----------------------Slave Defines -------------------------------------*/
#define S_DISCRETE_INPUT_START RT_S_DISCRETE_INPUT_START
#define S_DISCRETE_INPUT_NDISCRETES RT_S_DISCRETE_INPUT_NDISCRETES
#define S_COIL_START RT_S_COIL_START
#define S_COIL_NCOILS RT_S_COIL_NCOILS
#define S_REG_INPUT_START RT_S_REG_INPUT_START
#define S_REG_INPUT_NREGS RT_S_REG_INPUT_NREGS
#define S_REG_HOLDING_START RT_S_REG_HOLDING_START
#define S_REG_HOLDING_NREGS RT_S_REG_HOLDING_NREGS
/* salve mode: holding register's all address */
#define S_HD_RESERVE RT_S_HD_RESERVE
/* salve mode: input register's all address */
#define S_IN_RESERVE RT_S_IN_RESERVE
/* salve mode: coil's all address */
#define S_CO_RESERVE RT_S_CO_RESERVE
/* salve mode: discrete's all address */
#define S_DI_RESERVE RT_S_DI_RESERVE
/* -----------------------Master Defines -------------------------------------*/
#define M_DISCRETE_INPUT_START RT_M_DISCRETE_INPUT_START
#define M_DISCRETE_INPUT_NDISCRETES RT_M_DISCRETE_INPUT_NDISCRETES
#define M_COIL_START RT_M_COIL_START
#define M_COIL_NCOILS RT_M_COIL_NCOILS
#define M_REG_INPUT_START RT_M_REG_INPUT_START
#define M_REG_INPUT_NREGS RT_M_REG_INPUT_NREGS
#define M_REG_HOLDING_START RT_M_REG_HOLDING_START
#define M_REG_HOLDING_NREGS RT_M_REG_HOLDING_NREGS
/* master mode: holding register's all address */
#define M_HD_RESERVE RT_M_HD_RESERVE
/* master mode: input register's all address */
#define M_IN_RESERVE RT_M_IN_RESERVE
/* master mode: coil's all address */
#define M_CO_RESERVE RT_M_CO_RESERVE
/* master mode: discrete's all address */
#define M_DI_RESERVE RT_M_DI_RESERVE
#endif
#ifdef ADD_XIZI_FEATURES
/* -----------------------Slave Defines -------------------------------------*/
#define S_DISCRETE_INPUT_START X_S_DISCRETE_INPUT_START
#define S_DISCRETE_INPUT_NDISCRETES X_S_DISCRETE_INPUT_NDISCRETES
#define S_COIL_START X_S_COIL_START
#define S_COIL_NCOILS X_S_COIL_NCOILS
#define S_REG_INPUT_START X_S_REG_INPUT_START
#define S_REG_INPUT_NREGS X_S_REG_INPUT_NREGS
#define S_REG_HOLDING_START X_S_REG_HOLDING_START
#define S_REG_HOLDING_NREGS X_S_REG_HOLDING_NREGS
/* salve mode: holding register's all address */
#define S_HD_RESERVE X_S_HD_RESERVE
/* salve mode: input register's all address */
#define S_IN_RESERVE X_S_IN_RESERVE
/* salve mode: coil's all address */
#define S_CO_RESERVE X_S_CO_RESERVE
/* salve mode: discrete's all address */
#define S_DI_RESERVE X_S_DI_RESERVE
/* -----------------------Master Defines -------------------------------------*/
#define M_DISCRETE_INPUT_START X_M_DISCRETE_INPUT_START
#define M_DISCRETE_INPUT_NDISCRETES X_M_DISCRETE_INPUT_NDISCRETES
#define M_COIL_START X_M_COIL_START
#define M_COIL_NCOILS X_M_COIL_NCOILS
#define M_REG_INPUT_START X_M_REG_INPUT_START
#define M_REG_INPUT_NREGS X_M_REG_INPUT_NREGS
#define M_REG_HOLDING_START X_M_REG_HOLDING_START
#define M_REG_HOLDING_NREGS X_M_REG_HOLDING_NREGS
/* master mode: holding register's all address */
#define M_HD_RESERVE X_M_HD_RESERVE
/* master mode: input register's all address */
#define M_IN_RESERVE X_M_IN_RESERVE
/* master mode: coil's all address */
#define M_CO_RESERVE X_M_CO_RESERVE
/* master mode: discrete's all address */
#define M_DI_RESERVE X_M_DI_RESERVE
#endif
#endif

View File

@ -0,0 +1,294 @@
/*
* FreeModbus Libary: user callback functions and buffer define in master mode
* Copyright (C) 2013 Armink <armink.ztl@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id: user_mb_app_m.c,v 1.60 2013/11/23 11:49:05 Armink $
*/
#include "user_mb_app.h"
/*-----------------------Master mode use these variables----------------------*/
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
//Master mode:DiscreteInputs variables
USHORT usMDiscInStart = M_DISCRETE_INPUT_START;
#if M_DISCRETE_INPUT_NDISCRETES%8
UCHAR ucMDiscInBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_DISCRETE_INPUT_NDISCRETES/8+1];
#else
UCHAR ucMDiscInBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_DISCRETE_INPUT_NDISCRETES/8];
#endif
//Master mode:Coils variables
USHORT usMCoilStart = M_COIL_START;
#if M_COIL_NCOILS%8
UCHAR ucMCoilBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_COIL_NCOILS/8+1];
#else
UCHAR ucMCoilBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_COIL_NCOILS/8];
#endif
//Master mode:InputRegister variables
USHORT usMRegInStart = M_REG_INPUT_START;
USHORT usMRegInBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_REG_INPUT_NREGS];
//Master mode:HoldingRegister variables
USHORT usMRegHoldStart = M_REG_HOLDING_START;
USHORT usMRegHoldBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_REG_HOLDING_NREGS];
/**
* Modbus master input register callback function.
*
* @param pucRegBuffer input register buffer
* @param usAddress input register address
* @param usNRegs input register number
*
* @return result
*/
eMBErrorCode eMBMasterRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
{
eMBErrorCode eStatus = MB_ENOERR;
USHORT iRegIndex;
USHORT * pusRegInputBuf;
USHORT REG_INPUT_START;
USHORT REG_INPUT_NREGS;
USHORT usRegInStart;
pusRegInputBuf = usMRegInBuf[ucMBMasterGetDestAddress() - 1];
REG_INPUT_START = M_REG_INPUT_START;
REG_INPUT_NREGS = M_REG_INPUT_NREGS;
usRegInStart = usMRegInStart;
/* it already plus one in modbus function method. */
usAddress--;
if ((usAddress >= REG_INPUT_START)
&& (usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS))
{
iRegIndex = usAddress - usRegInStart;
while (usNRegs > 0)
{
pusRegInputBuf[iRegIndex] = *pucRegBuffer++ << 8;
pusRegInputBuf[iRegIndex] |= *pucRegBuffer++;
iRegIndex++;
usNRegs--;
}
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}
/**
* Modbus master holding register callback function.
*
* @param pucRegBuffer holding register buffer
* @param usAddress holding register address
* @param usNRegs holding register number
* @param eMode read or write
*
* @return result
*/
eMBErrorCode eMBMasterRegHoldingCB(UCHAR * pucRegBuffer, USHORT usAddress,
USHORT usNRegs, eMBRegisterMode eMode)
{
eMBErrorCode eStatus = MB_ENOERR;
USHORT iRegIndex;
USHORT * pusRegHoldingBuf;
USHORT REG_HOLDING_START;
USHORT REG_HOLDING_NREGS;
USHORT usRegHoldStart;
pusRegHoldingBuf = usMRegHoldBuf[ucMBMasterGetDestAddress() - 1];
REG_HOLDING_START = M_REG_HOLDING_START;
REG_HOLDING_NREGS = M_REG_HOLDING_NREGS;
usRegHoldStart = usMRegHoldStart;
/* if mode is read, the master will write the received date to buffer. */
eMode = MB_REG_WRITE;
/* it already plus one in modbus function method. */
usAddress--;
if ((usAddress >= REG_HOLDING_START)
&& (usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS))
{
iRegIndex = usAddress - usRegHoldStart;
switch (eMode)
{
/* read current register values from the protocol stack. */
case MB_REG_READ:
while (usNRegs > 0)
{
*pucRegBuffer++ = (UCHAR) (pusRegHoldingBuf[iRegIndex] >> 8);
*pucRegBuffer++ = (UCHAR) (pusRegHoldingBuf[iRegIndex] & 0xFF);
iRegIndex++;
usNRegs--;
}
break;
/* write current register values with new values from the protocol stack. */
case MB_REG_WRITE:
while (usNRegs > 0)
{
pusRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
pusRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
iRegIndex++;
usNRegs--;
}
break;
}
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}
/**
* Modbus master coils callback function.
*
* @param pucRegBuffer coils buffer
* @param usAddress coils address
* @param usNCoils coils number
* @param eMode read or write
*
* @return result
*/
eMBErrorCode eMBMasterRegCoilsCB(UCHAR * pucRegBuffer, USHORT usAddress,
USHORT usNCoils, eMBRegisterMode eMode)
{
eMBErrorCode eStatus = MB_ENOERR;
USHORT iRegIndex , iRegBitIndex , iNReg;
UCHAR * pucCoilBuf;
USHORT COIL_START;
USHORT COIL_NCOILS;
USHORT usCoilStart;
iNReg = usNCoils / 8 + 1;
pucCoilBuf = ucMCoilBuf[ucMBMasterGetDestAddress() - 1];
COIL_START = M_COIL_START;
COIL_NCOILS = M_COIL_NCOILS;
usCoilStart = usMCoilStart;
/* if mode is read,the master will write the received date to buffer. */
eMode = MB_REG_WRITE;
/* it already plus one in modbus function method. */
usAddress--;
if ((usAddress >= COIL_START)
&& (usAddress + usNCoils <= COIL_START + COIL_NCOILS))
{
iRegIndex = (USHORT) (usAddress - usCoilStart) / 8;
iRegBitIndex = (USHORT) (usAddress - usCoilStart) % 8;
switch (eMode)
{
/* read current coil values from the protocol stack. */
case MB_REG_READ:
while (iNReg > 0)
{
*pucRegBuffer++ = xMBUtilGetBits(&pucCoilBuf[iRegIndex++],
iRegBitIndex, 8);
iNReg--;
}
pucRegBuffer--;
/* last coils */
usNCoils = usNCoils % 8;
/* filling zero to high bit */
*pucRegBuffer = *pucRegBuffer << (8 - usNCoils);
*pucRegBuffer = *pucRegBuffer >> (8 - usNCoils);
break;
/* write current coil values with new values from the protocol stack. */
case MB_REG_WRITE:
while (iNReg > 1)
{
xMBUtilSetBits(&pucCoilBuf[iRegIndex++], iRegBitIndex, 8,
*pucRegBuffer++);
iNReg--;
}
/* last coils */
usNCoils = usNCoils % 8;
/* xMBUtilSetBits has bug when ucNBits is zero */
if (usNCoils != 0)
{
xMBUtilSetBits(&pucCoilBuf[iRegIndex++], iRegBitIndex, usNCoils,
*pucRegBuffer++);
}
break;
}
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}
/**
* Modbus master discrete callback function.
*
* @param pucRegBuffer discrete buffer
* @param usAddress discrete address
* @param usNDiscrete discrete number
*
* @return result
*/
eMBErrorCode eMBMasterRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
eMBErrorCode eStatus = MB_ENOERR;
USHORT iRegIndex , iRegBitIndex , iNReg;
UCHAR * pucDiscreteInputBuf;
USHORT DISCRETE_INPUT_START;
USHORT DISCRETE_INPUT_NDISCRETES;
USHORT usDiscreteInputStart;
iNReg = usNDiscrete / 8 + 1;
pucDiscreteInputBuf = ucMDiscInBuf[ucMBMasterGetDestAddress() - 1];
DISCRETE_INPUT_START = M_DISCRETE_INPUT_START;
DISCRETE_INPUT_NDISCRETES = M_DISCRETE_INPUT_NDISCRETES;
usDiscreteInputStart = usMDiscInStart;
/* it already plus one in modbus function method. */
usAddress--;
if ((usAddress >= DISCRETE_INPUT_START)
&& (usAddress + usNDiscrete <= DISCRETE_INPUT_START + DISCRETE_INPUT_NDISCRETES))
{
iRegIndex = (USHORT) (usAddress - usDiscreteInputStart) / 8;
iRegBitIndex = (USHORT) (usAddress - usDiscreteInputStart) % 8;
/* write current discrete values with new values from the protocol stack. */
while (iNReg > 1)
{
xMBUtilSetBits(&pucDiscreteInputBuf[iRegIndex++], iRegBitIndex, 8,
*pucRegBuffer++);
iNReg--;
}
/* last discrete */
usNDiscrete = usNDiscrete % 8;
/* xMBUtilSetBits has bug when ucNBits is zero */
if (usNDiscrete != 0)
{
xMBUtilSetBits(&pucDiscreteInputBuf[iRegIndex++], iRegBitIndex,
usNDiscrete, *pucRegBuffer++);
}
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}
#endif

View File

@ -0,0 +1,13 @@
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_RTU_MASTER),y)
SRC_FILES := sample_mb_master.c
endif
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_RTU_SLAVE),y)
SRC_FILES := sample_mb_slave.c
endif
ifeq ($(CONFIG_CONNECTION_MODBUS_USING_TCP_SLAVE),y)
SRC_FILES := sample_mb_slave.c
endif
include $(KERNEL_ROOT)/compiler.mk

View File

@ -0,0 +1,57 @@
# 示例代码说明
## 运行方法
### 配置工程
使用 Freemodbus 软件包示例代码,需要在 RT-Thread 的包管理器中选择它,并根据需要进行配置,具体路径如下:
```
RT-Thread online packages
IoT - internet of things --->
[*] FreeModbus: Modbus master and slave stack --->
[*] Master mode --->
[*] Enable RTU master mode
[*] Enable master sample
(1) Test slave device address
(2) uart number used by master sample, e.g. 2 means uart2
(115200) uart baudrate used by master sample
[*] Slave mode --->
[*] Enable RTU slave mode
[ ] Enable ASCII slave mode
[ ] Use Contorl Pin
[*] Enable slave sample
(1) Slave device address
(2) uart number used by slave sample, e.g. 2 means uart2
(115200) uart baudrate used by slave sample
```
添加示例代码到工程中,并编译下载之后,可以在控制台中看到这两个命令,分别是 Modbus 主机和从机的示例代码。要看代码运行的效果还需要 PC 端 Modbus Poll 和 Modbus slave 这两个软件的配合。
![1561348568591](figures/run.png)
### 运行主机示例
首先下载安装和主机示例代码配合的 Modbus slave 软件。
然后,在命令行输入 `mb_master_sample` 命令就可以运行主机的示例代码。
运行之后,打开 Modbus slave 软件点击菜单“Setup”中“Slave Definition.. F2”进行参数设置。
![img](figures/slave_cfg.png)
点击菜单“Connection”中“Connect.. F3”进行连接。弹出连接对话框根据具体情况配置
![1561351899477](figures/slave_con.png)
连接成功,可以看到寄存器列表中的第 2、3个寄存器的数值在不断变化。
![1561352048209](figures/slave_run.png)
### 运行从机示例
从机的运行示例和主机相差不大,只是 PC 端配合调试的软件,换成 Modbus Poll 即可。不再赘述。
## 注意事项
- 暂无

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -0,0 +1,226 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-06-21 flybreak first version
*/
/**
* @file sample_mb_master.c
* @brief support freemodbus port for XiUOS
* @version 3.0
* @author AIIT XUOS Lab
* @date 2023-10-12
*/
/*************************************************
File name: sample_mb_master.c
Description: support freemodbus port for XiUOS
Others:
History:
1. Date: 2023-10-12
Author: AIIT XUOS Lab
Modification:
1support XiUOS for master demo.
*************************************************/
#include <transform.h>
#ifdef ADD_RTTHREAD_FEATURES
#include <rtthread.h>
#endif
#include "mb.h"
#include "mb_m.h"
#ifdef ADD_RTTHREAD_FEATURES
#ifdef PKG_MODBUS_MASTER_SAMPLE
#define SLAVE_ADDR MB_SAMPLE_TEST_SLAVE_ADDR
#define PORT_NUM MB_MASTER_USING_PORT_NUM
#define PORT_BAUDRATE MB_MASTER_USING_PORT_BAUDRATE
#else
#define SLAVE_ADDR 0x01
#define PORT_NUM 3
#define PORT_BAUDRATE 115200
#endif
#define PORT_PARITY MB_PAR_EVEN
#define MB_POLL_THREAD_PRIORITY 10
#define MB_SEND_THREAD_PRIORITY RT_THREAD_PRIORITY_MAX - 1
#define MB_SEND_REG_START 2
#define MB_SEND_REG_NUM 2
#define MB_POLL_CYCLE_MS 500
static void send_thread_entry(void *parameter)
{
eMBMasterReqErrCode error_code = MB_MRE_NO_ERR;
rt_uint16_t error_count = 0;
USHORT data[MB_SEND_REG_NUM] = {0};
while (1)
{
/* Test Modbus Master */
data[0] = (USHORT)(rt_tick_get() / 10);
data[1] = (USHORT)(rt_tick_get() % 10);
error_code = eMBMasterReqWriteMultipleHoldingRegister(SLAVE_ADDR, /* salve address */
MB_SEND_REG_START, /* register start address */
MB_SEND_REG_NUM, /* register total number */
data, /* data to be written */
RT_WAITING_FOREVER); /* timeout */
/* Record the number of errors */
if (error_code != MB_MRE_NO_ERR)
{
error_count++;
}
}
}
static void mb_master_poll(void *parameter)
{
eMBMasterInit(MB_RTU, PORT_NUM, PORT_BAUDRATE, PORT_PARITY);
eMBMasterEnable();
while (1)
{
eMBMasterPoll();
rt_thread_mdelay(MB_POLL_CYCLE_MS);
}
}
static int mb_master_sample(int argc, char **argv)
{
static rt_uint8_t is_init = 0;
rt_thread_t tid1 = RT_NULL, tid2 = RT_NULL;
if (is_init > 0)
{
rt_kprintf("sample is running\n");
return -RT_ERROR;
}
tid1 = rt_thread_create("md_m_poll", mb_master_poll, RT_NULL, 512, MB_POLL_THREAD_PRIORITY, 10);
if (tid1 != RT_NULL)
{
rt_thread_startup(tid1);
}
else
{
goto __exit;
}
tid2 = rt_thread_create("md_m_send", send_thread_entry, RT_NULL, 512, MB_SEND_THREAD_PRIORITY, 10);
if (tid2 != RT_NULL)
{
rt_thread_startup(tid2);
}
else
{
goto __exit;
}
is_init = 1;
return RT_EOK;
__exit:
if (tid1)
rt_thread_delete(tid1);
if (tid2)
rt_thread_delete(tid2);
return -RT_ERROR;
}
MSH_CMD_EXPORT(mb_master_sample, run a modbus master sample);
#endif
#ifdef ADD_XIZI_FEATURES
#define SLAVE_ADDR 0x01
#define PORT_NUM 4
#define PORT_BAUDRATE 115200
#define PORT_PARITY MB_PAR_NONE
#define MB_POLL_THREAD_PRIORITY 22
#define MB_SEND_THREAD_PRIORITY 22
#define MB_SEND_REG_START 2
#define MB_SEND_REG_NUM 2
#define MB_POLL_CYCLE_MS 500
static pthread_t tid1, tid2;
static void *send_thread_entry(void *parameter)
{
eMBMasterReqErrCode error_code = MB_MRE_NO_ERR;
uint16_t error_count = 0;
USHORT data[MB_SEND_REG_NUM] = {0};
while (1) {
/* Test Modbus Master */
data[0] = (USHORT)(PrivGetTickTime() / 10);
data[1] = (USHORT)(PrivGetTickTime() % 10);
error_code = eMBMasterReqWriteMultipleHoldingRegister(SLAVE_ADDR, /* salve address */
MB_SEND_REG_START, /* register start address */
MB_SEND_REG_NUM, /* register total number */
data, /* data to be written */
0); /* timeout */
/* Record the number of errors */
if (error_code != MB_MRE_NO_ERR) {
error_count++;
}
}
}
static void *mb_master_poll(void *parameter)
{
eMBMasterInit(MB_RTU, PORT_NUM, PORT_BAUDRATE, PORT_PARITY);
eMBMasterEnable();
while (1) {
eMBMasterPoll();
PrivTaskDelay(MB_POLL_CYCLE_MS);
}
}
static int mb_master_sample(void)
{
static uint8_t is_init = 0;
if (is_init > 0) {
printf("sample is running\n");
return -1;
}
pthread_attr_t attr;
attr.schedparam.sched_priority = MB_POLL_THREAD_PRIORITY;
attr.stacksize = 2048;
char task1_name[] = "md_m_poll";
pthread_args_t args;
args.pthread_name = task1_name;
PrivTaskCreate(&tid1, &attr, &mb_master_poll, (void *)&args);
PrivTaskStartup(&tid1);
attr.schedparam.sched_priority = MB_SEND_THREAD_PRIORITY;
attr.stacksize = 2048;
char task2_name[] = "md_m_send";
args.pthread_name = task2_name;
PrivTaskCreate(&tid2, &attr, &send_thread_entry, (void *)&args);
PrivTaskStartup(&tid2);
is_init = 1;
return 0;
}
PRIV_SHELL_CMD_FUNCTION(mb_master_sample, run a modbus master sample, PRIV_SHELL_CMD_MAIN_ATTR);
#endif

View File

@ -0,0 +1,246 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-06-21 flybreak first version
*/
/**
* @file sample_mb_slave.c
* @brief support freemodbus port for XiUOS
* @version 3.0
* @author AIIT XUOS Lab
* @date 2023-10-12
*/
/*************************************************
File name: sample_mb_slave.c
Description: support freemodbus port for XiUOS
Others:
History:
1. Date: 2023-10-12
Author: AIIT XUOS Lab
Modification:
1support XiUOS for slave demo.
*************************************************/
#include <transform.h>
#ifdef ADD_RTTHREAD_FEATURES
#include <rtthread.h>
#endif
#include "mb.h"
#include "user_mb_app.h"
#ifdef ADD_RTTHREAD_FEATURES
#ifdef PKG_MODBUS_SLAVE_SAMPLE
#define SLAVE_ADDR MB_SAMPLE_SLAVE_ADDR
#define PORT_NUM MB_SLAVE_USING_PORT_NUM
#define PORT_BAUDRATE MB_SLAVE_USING_PORT_BAUDRATE
#else
#define SLAVE_ADDR 0x01
#define PORT_NUM 2
#define PORT_BAUDRATE 115200
#endif
#define PORT_PARITY MB_PAR_EVEN
#define MB_POLL_THREAD_PRIORITY 10
#define MB_SEND_THREAD_PRIORITY RT_THREAD_PRIORITY_MAX - 1
#define MB_POLL_CYCLE_MS 200
extern USHORT usSRegHoldBuf[S_REG_HOLDING_NREGS];
static void send_thread_entry(void *parameter)
{
USHORT *usRegHoldingBuf;
usRegHoldingBuf = usSRegHoldBuf;
rt_base_t level;
while (1)
{
/* Test Modbus Master */
level = rt_hw_interrupt_disable();
usRegHoldingBuf[3] = (USHORT)(rt_tick_get() / 100);
rt_hw_interrupt_enable(level);
rt_thread_mdelay(1000);
}
}
static void mb_slave_poll(void *parameter)
{
if (rt_strstr(parameter, "RTU"))
{
#ifdef PKG_MODBUS_SLAVE_RTU
eMBInit(MB_RTU, SLAVE_ADDR, PORT_NUM, PORT_BAUDRATE, PORT_PARITY);
#else
rt_kprintf("Error: Please open RTU mode first");
#endif
}
else if (rt_strstr(parameter, "ASCII"))
{
#ifdef PKG_MODBUS_SLAVE_ASCII
eMBInit(MB_ASCII, SLAVE_ADDR, PORT_NUM, PORT_BAUDRATE, PORT_PARITY);
#else
rt_kprintf("Error: Please open ASCII mode first");
#endif
}
else if (rt_strstr(parameter, "TCP"))
{
#ifdef PKG_MODBUS_SLAVE_TCP
eMBTCPInit(0);
#else
rt_kprintf("Error: Please open TCP mode first");
#endif
}
else
{
rt_kprintf("Error: unknown parameter");
}
eMBEnable();
while (1)
{
eMBPoll();
rt_thread_mdelay(MB_POLL_CYCLE_MS);
}
}
static int mb_slave_sample(int argc, char **argv)
{
static rt_uint8_t is_init = 0;
rt_thread_t tid1 = RT_NULL, tid2 = RT_NULL;
if (is_init > 0)
{
rt_kprintf("sample is running\n");
return -RT_ERROR;
}
if (argc < 2)
{
rt_kprintf("Usage: mb_slave_sample RTU/ASCII/TCP\n");
return -1;
}
tid1 = rt_thread_create("md_s_poll", mb_slave_poll, argv[1], 1024, MB_POLL_THREAD_PRIORITY, 10);
if (tid1 != RT_NULL)
{
rt_thread_startup(tid1);
}
else
{
goto __exit;
}
tid2 = rt_thread_create("md_s_send", send_thread_entry, RT_NULL, 512, MB_SEND_THREAD_PRIORITY, 10);
if (tid2 != RT_NULL)
{
rt_thread_startup(tid2);
}
else
{
goto __exit;
}
is_init = 1;
return RT_EOK;
__exit:
if (tid1)
rt_thread_delete(tid1);
if (tid2)
rt_thread_delete(tid2);
return -RT_ERROR;
}
MSH_CMD_EXPORT(mb_slave_sample, run a modbus slave sample);
#endif
#ifdef ADD_XIZI_FEATURES
#define SLAVE_ADDR 0x01
#define PORT_NUM 4
#define PORT_BAUDRATE 115200
#define PORT_PARITY MB_PAR_NONE
#define MB_POLL_THREAD_PRIORITY 22
#define MB_SEND_THREAD_PRIORITY 22
#define MB_POLL_CYCLE_MS 200
extern USHORT usSRegHoldBuf[S_REG_HOLDING_NREGS];
static pthread_t tid1, tid2;
static void *send_thread_entry(void *parameter)
{
USHORT *usRegHoldingBuf;
usRegHoldingBuf = usSRegHoldBuf;
int level;
while (1) {
/* Test Modbus Master */
level = DISABLE_INTERRUPT();
usRegHoldingBuf[3] = (USHORT)(PrivGetTickTime() / 100);
ENABLE_INTERRUPT(level);
PrivTaskDelay(1000);
}
}
static void *mb_slave_poll(void *parameter)
{
eMBInit(MB_RTU, SLAVE_ADDR, PORT_NUM, PORT_BAUDRATE, PORT_PARITY);
eMBEnable();
while (1) {
eMBPoll();
PrivTaskDelay(MB_POLL_CYCLE_MS);
}
}
static int mb_slave_sample(void)
{
static uint8_t is_init = 0;
if (is_init > 0) {
printf("sample is running\n");
return -1;
}
pthread_attr_t attr;
attr.schedparam.sched_priority = MB_POLL_THREAD_PRIORITY;
attr.stacksize = 2048;
char task1_name[] = "md_s_poll";
pthread_args_t args;
args.arg = NULL;
args.pthread_name = task1_name;
PrivTaskCreate(&tid1, &attr, &mb_slave_poll, (void *)&args);
PrivTaskStartup(&tid1);
attr.schedparam.sched_priority = MB_SEND_THREAD_PRIORITY;
attr.stacksize = 2048;
char task2_name[] = "md_s_send";
args.arg = NULL;
args.pthread_name = task2_name;
PrivTaskCreate(&tid2, &attr, &send_thread_entry, (void *)&args);
PrivTaskStartup(&tid2);
is_init = 1;
return 0;
}
PRIV_SHELL_CMD_FUNCTION(mb_slave_sample, run a modbus slave sample, PRIV_SHELL_CMD_MAIN_ATTR);
#endif

View File

@ -1,144 +0,0 @@
/*
* Copyright (c) 2020 AIIT XUOS Lab
* XiUOS is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
/**
* @file modbus_rtu.c
* @brief Implement the connection Modbus RTU adapter function, using Modbus rtu device
* @version 1.1
* @author AIIT XUOS Lab
* @date 2021.07.08
*/
#include <adapter.h>
#define PLC_DATA_LENGTH 1024
struct CircularAreaApp *g_circular_area;
static pthread_t recv_plc_data_task;
/**
* @description: Open modbus rtu function
* @param adapter - Modbus RTU device pointer
* @return success: 0, failure: -1
*/
static int ModbusRtuOpen(struct Adapter *adapter)
{
/* open serial port*/
adapter->fd = PrivOpen("/dev/tty3", 2);//2 read and write
if (adapter->fd < 0) {
printf("ModbusRtuOpen get serial %s fd error\n", "/dev/tty3");
return -1;
}
PrivTaskDelay(2500);
ADAPTER_DEBUG("Modbus rtu open done\n");
return 0;
}
/**
* @description: Close modbus rtu function
* @param adapter - Modbus RTu device pointer
* @return success: 0, failure: -1
*/
static int ModbusRtuClose(struct Adapter *adapter)
{
/*step1: close modbus serial port*/
int ret;
ret = PrivClose(adapter->fd);
if(ret < 0){
printf("ModbusRtuOpen close serial %s fd error\n", "/dev/tty3");
return -1;
}
ADAPTER_DEBUG("Modbus rtu Close done\n");
return 0;
}
static int ModbusRtuIoctl(struct Adapter *adapter, int cmd)
{
// uint32_t baud_rate = *((uint32_t *)args);
struct SerialDataCfg serial_cfg;
memset(&serial_cfg, 0 ,sizeof(struct SerialDataCfg));
serial_cfg.serial_baud_rate = BAUD_RATE_9600 ;
serial_cfg.serial_data_bits = DATA_BITS_8;
serial_cfg.serial_stop_bits = STOP_BITS_1;
serial_cfg.serial_buffer_size = SERIAL_RB_BUFSZ;
serial_cfg.serial_parity_mode = PARITY_EVEN;
serial_cfg.serial_bit_order = STOP_BITS_1;
serial_cfg.serial_invert_mode = NRZ_NORMAL;
serial_cfg.is_ext_uart = 0;
struct PrivIoctlCfg ioctl_cfg;
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
ioctl_cfg.args = &serial_cfg;
PrivIoctl(adapter->fd, OPE_INT, &ioctl_cfg);
return 0;
}
static int ModbusRtuSend(struct Adapter *adapter, const void *buf, size_t len)
{
int ret;
ret = PrivWrite(adapter->fd, buf, len);
if(ret < 0){
printf("send failed %d!\n", ret);
}
return ret;
}
static int ModbusRtuRecv(struct Adapter *adapter, void *buf, size_t len)
{
int recv_len=0, recv_len_continue=0;
uint8 *recv_buf = PrivMalloc(len);
recv_len = PrivRead(adapter->fd, recv_buf, len);
if (recv_len) {
while (recv_len < len) {
recv_len_continue = PrivRead(adapter->fd, recv_buf + recv_len, len - recv_len);
if (recv_len_continue) {
recv_len += recv_len_continue;
} else {
recv_len = 0;
break;
}
}
memcpy(buf, recv_buf, len);
}
PrivFree(recv_buf);
return recv_len;
}
static const struct IpProtocolDone ec200t_done =
{
.open = ModbusRtuOpen,
.close = ModbusRtuClose,
.ioctl = ModbusRtuIoctl,
.setup = NULL,
.setdown = NULL,
.setaddr = NULL,
.setdns = NULL,
.setdhcp = NULL,
.ping = NULL,
.netstat = NULL,
.connect = NULL,
.send = ModbusRtuSend,
.recv = ModbusRtuRecv,
.disconnect = NULL,
};

View File

@ -290,6 +290,7 @@ static int E22Open(struct Adapter *adapter)
//serial receive wait forever
cfg.serial_timeout = -1;
#endif
cfg.dev_recv_callback = NULL;
struct PrivIoctlCfg ioctl_cfg;
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;

View File

@ -374,6 +374,7 @@ static int E220Open(struct Adapter *adapter)
//serial receive wait forever
cfg.serial_timeout = -1;
#endif
cfg.dev_recv_callback = NULL;
struct PrivIoctlCfg ioctl_cfg;
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
@ -428,6 +429,7 @@ static int E220Open(struct Adapter *adapter)
//serial receive wait forever
cfg.serial_timeout = -1;
#endif
cfg.dev_recv_callback = NULL;
struct PrivIoctlCfg ioctl_cfg;
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;

View File

@ -63,6 +63,7 @@ static int BC28UartOpen(struct Adapter *adapter)
cfg.ext_uart_no = ADAPTER_BC28_DRIVER_EXT_PORT;
cfg.port_configure = PORT_CFG_INIT;
#endif
cfg.dev_recv_callback = NULL;
struct PrivIoctlCfg ioctl_cfg;
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;

View File

@ -81,6 +81,7 @@ static int Esp07sUartOpen(struct Adapter *adapter)
cfg.ext_uart_no = ADAPTER_ESP07S_DRIVER_EXT_PORT;
cfg.port_configure = PORT_CFG_INIT;
#endif
cfg.dev_recv_callback = NULL;
struct PrivIoctlCfg ioctl_cfg;
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
@ -527,6 +528,7 @@ static int Esp07sWifiIoctl(struct Adapter *adapter, int cmd, void *args)
cfg.serial_invert_mode = NRZ_NORMAL;
cfg.serial_buffer_size = SERIAL_RB_BUFSZ;
cfg.is_ext_uart = 0;
cfg.dev_recv_callback = NULL;
#ifdef ADAPTER_ESP07S_DRIVER_EXT_PORT
cfg.is_ext_uart = 1;
cfg.ext_uart_no = ADAPTER_ESP07S_DRIVER_EXT_PORT;

View File

@ -81,6 +81,7 @@ static int Esp8285UartOpen(struct Adapter *adapter)
cfg.ext_uart_no = ADAPTER_ESP8285_DRIVER_EXT_PORT;
cfg.port_configure = PORT_CFG_INIT;
#endif
cfg.dev_recv_callback = NULL;
struct PrivIoctlCfg ioctl_cfg;
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
@ -507,6 +508,7 @@ static int Esp8285WifiIoctl(struct Adapter *adapter, int cmd, void *args)
cfg.serial_invert_mode = NRZ_NORMAL;
cfg.serial_buffer_size = SERIAL_RB_BUFSZ;
cfg.is_ext_uart = 0;
cfg.dev_recv_callback = NULL;
#ifdef ADAPTER_ESP8285_DRIVER_EXT_PORT
cfg.is_ext_uart = 1;
cfg.ext_uart_no = ADAPTER_ESP8285_DRIVER_EXT_PORT;

View File

@ -479,6 +479,7 @@ static int Hfa21WifiIoctl(struct Adapter *adapter, int cmd, void *args)
serial_cfg.ext_uart_no = ADAPTER_HFA21_DRIVER_EXT_PORT;
serial_cfg.port_configure = PORT_CFG_INIT;
#endif
serial_cfg.dev_recv_callback = NULL;
struct PrivIoctlCfg ioctl_cfg;
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;

View File

@ -160,6 +160,7 @@ static int E18UartOpen(struct Adapter *adapter)
cfg.ext_uart_no = ADAPTER_E18_DRIVER_EXT_PORT;
cfg.port_configure = PORT_CFG_INIT;
#endif
cfg.dev_recv_callback = NULL;
struct PrivIoctlCfg ioctl_cfg;
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;

View File

@ -97,6 +97,7 @@ void Uart485Init(uint32_t baud_rate, uint8_t data_bits, uint8_t stop_bits, uint8
cfg.port_configure = PORT_CFG_INIT;
#endif
cfg.serial_timeout = 10000;
cfg.dev_recv_callback = NULL;
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
ioctl_cfg.args = &cfg;

View File

@ -58,6 +58,7 @@ static int SensorDeviceOpen(struct SensorDevice *sdev)
cfg.ext_uart_no = SENSOR_DEVICE_AS830_DEV_EXT_PORT;
cfg.port_configure = PORT_CFG_INIT;
#endif
cfg.dev_recv_callback = NULL;
struct PrivIoctlCfg ioctl_cfg;
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;

View File

@ -62,6 +62,7 @@ static int SensorDeviceOpen(struct SensorDevice *sdev)
cfg.ext_uart_no = SENSOR_DEVICE_G8S_DEV_EXT_PORT;
cfg.port_configure = PORT_CFG_INIT;
#endif
cfg.dev_recv_callback = NULL;
struct PrivIoctlCfg ioctl_cfg;
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;

View File

@ -62,6 +62,7 @@ static int SensorDeviceOpen(struct SensorDevice *sdev)
cfg.ext_uart_no = SENSOR_DEVICE_ZG09_DEV_EXT_PORT;
cfg.port_configure = PORT_CFG_INIT;
#endif
cfg.dev_recv_callback = NULL;
struct PrivIoctlCfg ioctl_cfg;
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;

View File

@ -59,6 +59,7 @@ static int SensorDeviceOpen(struct SensorDevice *sdev)
cfg.ext_uart_no = SENSOR_DEVICE_TB600B_WQ_HCHO1OS_DEV_EXT_PORT;
cfg.port_configure = PORT_CFG_INIT;
#endif
cfg.dev_recv_callback = NULL;
struct PrivIoctlCfg ioctl_cfg;
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;

View File

@ -67,6 +67,7 @@ static int SensorDeviceOpen(struct SensorDevice *sdev)
cfg.ext_uart_no = SENSOR_DEVICE_TB600B_IAQ10_DEV_EXT_PORT;
cfg.port_configure = PORT_CFG_INIT;
#endif
cfg.dev_recv_callback = NULL;
struct PrivIoctlCfg ioctl_cfg;
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;

View File

@ -77,6 +77,7 @@ static int SensorDeviceOpen(struct SensorDevice *sdev)
cfg.ext_uart_no = SENSOR_DEVICE_PS5308_DEV_EXT_PORT;
cfg.port_configure = PORT_CFG_INIT;
#endif
cfg.dev_recv_callback = NULL;
result = PrivIoctl(sdev->fd, OPE_INT, &cfg);

View File

@ -59,6 +59,7 @@ static int SensorDeviceOpen(struct SensorDevice *sdev)
cfg.ext_uart_no = SENSOR_DEVICE_TB600B_TVOC10_DEV_EXT_PORT;
cfg.port_configure = PORT_CFG_INIT;
#endif
cfg.dev_recv_callback = NULL;
struct PrivIoctlCfg ioctl_cfg;
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;

View File

@ -107,6 +107,7 @@ static int SensorDeviceOpen(struct SensorDevice *sdev)
cfg.ext_uart_no = SENSOR_DEVICE_D124_DEV_EXT_PORT;
cfg.port_configure = PORT_CFG_INIT;
#endif
cfg.dev_recv_callback = NULL;
struct PrivIoctlCfg ioctl_cfg;
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;

Some files were not shown because too many files have changed in this diff Show More