apps/eamples/modbusmaster: Add Simple Modbus master example. This example only supports Read/Write HoldingRegisters, but it is easy to extend it to support Read/Write Input/Coils/etc. Originally creatd bey Vytautas in 2016 and updated with minor fixes for this commit.

This commit is contained in:
Alan Carvalho de Assis 2019-02-02 08:17:36 -06:00 committed by Gregory Nutt
parent 721bb64e52
commit 87f42accc6
5 changed files with 517 additions and 0 deletions

11
examples/modbusmaster/.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
/Make.dep
/.depend
/.built
/*.asm
/*.obj
/*.rel
/*.lst
/*.sym
/*.adb
/*.lib
/*.src

View File

@ -0,0 +1,62 @@
#
# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#
config EXAMPLES_MODBUSMASTER
bool "Modbus Master example"
default n
---help---
Enable the Modbus Master example
if EXAMPLES_MODBUSMASTER
config EXAMPLES_MODBUSMASTER_PROGNAME
string "Program name"
default "modbusmaster"
depends on BUILD_KERNEL
---help---
This is the name of the program that will be use when the NSH ELF
program is installed.
config EXAMPLES_MODBUSMASTER_PRIORITY
int "Modbus Master task priority"
default 100
config EXAMPLES_MODBUSMASTER_STACKSIZE
int "Modbus Master stack size"
default 2048
config EXAMPLES_MODBUSMASTER_PORT
int "Modbus Master port (1 for /dev/ttyS1)"
default 1
---help---
Choose Modbus master communications port. 0 corresponds
/dev/ttyS0, 1 -- /dev/ttyS1, etc.
config EXAMPLES_MODBUSMASTER_BAUDRATE
int "Modbus Master port Baudrate"
default 38400
---help---
Choose modbus master serial port baudrate.
config EXAMPLES_MODBUSMASTER_PARITY
int "Modbus Master port Parity"
default 2
---help---
Choose Modbus master serial port parity.
0 = NONE ; 1 = ODD; 2 = EVEN
config EXAMPLES_MODBUSMASTER_SLAVEADDR
int "Modbus Slave Address (master will query this slave)"
default 1
config EXAMPLES_MODBUSMASTER_SLAVEREG
int "Modbus Slave Holding Register address to query"
default 1
config EXAMPLES_MODBUSMASTER_TESTCOUNT
int "Reads count to perform"
default 100
endif

View File

@ -0,0 +1,39 @@
############################################################################
# apps/examples/modbusmaster/Make.defs
# Adds selected applications to apps/ build
#
# Copyright (C) 2019 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt <gnutt@nuttx.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name NuttX nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
ifeq ($(CONFIG_EXAMPLES_MODBUSMASTER),y)
CONFIGURED_APPS += examples/modbusmaster
endif

View File

@ -0,0 +1,56 @@
############################################################################
# apps/examples/modbusmaster/Makefile
#
# Copyright (C) 2019 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt <gnutt@nuttx.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name NuttX nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
-include $(TOPDIR)/Make.defs
# Modbus Master built-in application info
CONFIG_EXAMPLES_MODBUSMASTER_PRIORITY ?= SCHED_PRIORITY_DEFAULT
CONFIG_EXAMPLES_MODBUSMASTER_STACKSIZE ?= 2048
APPNAME = mbmaster
PRIORITY = $(CONFIG_EXAMPLES_MODBUSMASTER_PRIORITY)
STACKSIZE = $(CONFIG_EXAMPLES_MODBUSMASTER_STACKSIZE)
# Modbus Master Example
ASRCS =
CSRCS =
MAINSRC = mbmaster_main.c
CONFIG_EXAMPLES_MODBUSMASTER_PROGNAME ?= mbmaster$(EXEEXT)
PROGNAME = $(CONFIG_EXAMPLES_MODBUSMASTER_PROGNAME)
include $(APPDIR)/Application.mk

View File

@ -0,0 +1,349 @@
/****************************************************************************
* apps/examples/modbusmaster/mbmaster_main.c
*
* Copyright (c) 2016 Vytautas Lukenskas <lukevyta@gmail.com>
* Copyright (c) 2019 Alan Carvalho de Assis <acassis@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <errno.h>
#include "modbus/mb.h"
#include "modbus/mb_m.h"
#include "modbus/mbport.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* modbus master port */
#ifdef CONFIG_EXAMPLES_MODBUSMASTER_PORT
# define MBMASTER_PORT CONFIG_EXAMPLES_MODBUSMASTER_PORT
#else
# define MBMASTER_PORT 1 /* port, 1 -- /dev/ttyS1 */
#endif
#ifdef CONFIG_EXAMPLES_MODBUSMASTER_BAUDRATE
# define MBMASTER_BAUD CONFIG_EXAMPLES_MODBUSMASTER_BAUDRATE
#else
# define MBMASTER_BAUD B115200 /* baudrate, 115200kbps */
#endif
#ifdef CONFIG_EXAMPLES_MODBUSMASTER_PARITY
# define MBMASTER_PARITY CONFIG_EXAMPLES_MODBUSMASTER_PARITY
#else
# define MBMASTER_PARITY MB_PAR_EVEN /* parity, even */
#endif
#ifdef CONFIG_EXAMPLES_MODBUSMASTER_SLAVEADDR
# define SLAVE_ID CONFIG_EXAMPLES_MODBUSMASTER_SLAVEADDR
#else
# define SLAVE_ID 1 /* slave address */
#endif
#ifdef CONFIG_EXAMPLES_MODBUSMASTER_SLAVEREG
# define SLAVE_STATUS_REG CONFIG_EXAMPLES_MODBUSMASTER_SLAVEREG
#else
# define SLAVE_STATUS_REG 1 /* slave status register part1 */
#endif
#ifdef CONFIG_EXAMPLES_MODBUSMASTER_TESTCOUT
# define MBMASTER_REQUESTS_COUNT CONFIG_EXAMPLES_MODBUSMASTER_TESTCOUT
#else
# define MBMASTER_REQUESTS_COUNT 100 /* number of requests to send */
#endif
/****************************************************************************
* Private Types
****************************************************************************/
enum mbmaster_threadcmd_e
{
STOPPED = 0,
RUN,
SHUTDOWN
};
struct mbmaster_statistics_s
{
int reqcount;
int rspcount;
int errcount;
};
struct mbmaster_run_s
{
pthread_t pollthreadid;
enum mbmaster_threadcmd_e threadcmd;
struct mbmaster_statistics_s statistics;
};
/****************************************************************************
* Private Global Variables
****************************************************************************/
static struct mbmaster_run_s g_mbmaster;
/****************************************************************************
* Private functions
****************************************************************************/
/****************************************************************************
* Name: mbmaster_initialize
*
* Description:
* Should initialize modbus stack.
*
****************************************************************************/
static inline int mbmaster_initialize(void)
{
eMBErrorCode mberr;
/* Initialize the FreeModBus library (master) */
mberr = eMBMasterInit(MB_RTU, MBMASTER_PORT,
MBMASTER_BAUD, MBMASTER_PARITY);
if (mberr != MB_ENOERR)
{
fprintf(stderr, "mbmaster_main: "
"ERROR: eMBMasterInit failed: %d\n", mberr);
return ENODEV;
}
/* Enable FreeModBus Master */
mberr = eMBMasterEnable();
if (mberr != MB_ENOERR)
{
fprintf(stderr, "mbmaster_main: "
"ERROR: eMBMasterEnable failed: %d\n", mberr);
return ENODEV;
}
return OK;
}
/****************************************************************************
* Name: mbmaster_deinitialize
*
* Description:
* Should release resources taken by modbus stack.
*
****************************************************************************/
static inline void mbmaster_deinitialize(void)
{
/* Disable modbus stack */
(void)eMBMasterDisable();
/* Release hardware resources */
(void)eMBMasterClose();
}
/****************************************************************************
* Name: mbmaster_pollthread
*
* Description:
* This is the ModBus Master polling thread.
*
****************************************************************************/
static FAR void *mbmaster_pollthread(FAR void *pvarg)
{
eMBErrorCode mberr;
do
{
/* Poll */
mberr = eMBMasterPoll();
if (mberr != MB_ENOERR)
{
break;
}
}
while (g_mbmaster.threadcmd != SHUTDOWN);
/* Free/uninitialize data structures */
g_mbmaster.threadcmd = STOPPED;
printf("mbmaster_main: "
"Exiting poll thread.\n");
return NULL;
}
/****************************************************************************
* Name: mbmaster_showstatistics
*
* Description:
* Show final connection statistics
*
****************************************************************************/
static void mbmaster_showstatistics(void)
{
printf("Modbus master statistics: \n");
printf("Requests count: %d\n", g_mbmaster.statistics.reqcount);
printf("Responses count: %d\n", g_mbmaster.statistics.rspcount);
printf("Errors count: %d\n", g_mbmaster.statistics.errcount);
}
/****************************************************************************
* Name: eMBMasterRegHoldingCB
*
* Description:
* Required FreeModBus callback function
*
****************************************************************************/
static eMBErrorCode eMBMasterRegHoldingCB(FAR uint8_t *buffer,
uint16_t address, uint16_t nregs,
eMBRegisterMode mode)
{
eMBErrorCode mberr = MB_ENOERR;
switch (mode)
{
case MB_REG_READ:
g_mbmaster.statistics.rspcount++;
break;
case MB_REG_WRITE:
printf("mbmaster_main: writing holding register, value: %d\n",
*(buffer));
break;
}
return mberr;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: main/mbmaster_main
****************************************************************************/
#ifdef CONFIG_BUILD_KERNEL
int main(int argc, FAR char *argv[])
#else
int mbmaster_main(int argc, FAR char *argv[])
#endif
{
eMBMasterReqErrCode mberr;
int reqcounter = 0;
int ret;
g_mbmaster.statistics.reqcount = 0;
g_mbmaster.statistics.rspcount = 0;
g_mbmaster.statistics.errcount = 0;
g_mbmaster.threadcmd = STOPPED;
reqcounter = 0;
/* Initialize modbus stack, etc */
printf("Initializing modbus master...\n");
ret = mbmaster_initialize();
if (ret != OK)
{
fprintf(stderr, "mbmaster_main: ",
"ERROR: mbmaster_initialize failed: %d\n", ret);
goto errout;
}
printf("Creating poll thread.\n");
g_mbmaster.threadcmd = RUN;
ret = pthread_create(&g_mbmaster.pollthreadid, NULL,
mbmaster_pollthread, NULL);
if (ret != OK)
{
fprintf(stderr, "mbmaster_main: ",
"ERROR: mbmaster_pollthread create failed: %d\n", ret);
goto errout_with_initialize;
}
printf("Sending %d requests to slave %d\n",
MBMASTER_REQUESTS_COUNT, SLAVE_ID);
/* modbus is initialized and polling thread is running */
while (reqcounter < MBMASTER_REQUESTS_COUNT)
{
g_mbmaster.statistics.reqcount++;
mberr = eMBMasterReqReadHoldingRegister(SLAVE_ID,
SLAVE_STATUS_REG, 1, -1);
if (mberr != MB_MRE_NO_ERR)
{
fprintf(stderr, "mbmaster_main: "
"ERROR: holding reg %d read failed: %d\n",
SLAVE_STATUS_REG, mberr);
g_mbmaster.statistics.errcount++;
}
reqcounter++;
}
/* Stop polling thread */
g_mbmaster.threadcmd = SHUTDOWN;
pthread_join(g_mbmaster.pollthreadid, NULL);
g_mbmaster.threadcmd = STOPPED;
/* Display connection statistics */
mbmaster_showstatistics();
printf("Deinitializing modbus master...\n");
mbmaster_deinitialize();
return OK;
errout_with_initialize:
/* Release hardware resources */
mbmaster_deinitialize();
errout:
exit(EXIT_FAILURE);
}