From 87f42accc629d44ebbc5ca23c61fb3981c2d1e91 Mon Sep 17 00:00:00 2001 From: Alan Carvalho de Assis Date: Sat, 2 Feb 2019 08:17:36 -0600 Subject: [PATCH] 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. --- examples/modbusmaster/.gitignore | 11 + examples/modbusmaster/Kconfig | 62 +++++ examples/modbusmaster/Make.defs | 39 +++ examples/modbusmaster/Makefile | 56 +++++ examples/modbusmaster/mbmaster_main.c | 349 ++++++++++++++++++++++++++ 5 files changed, 517 insertions(+) create mode 100644 examples/modbusmaster/.gitignore create mode 100644 examples/modbusmaster/Kconfig create mode 100644 examples/modbusmaster/Make.defs create mode 100644 examples/modbusmaster/Makefile create mode 100644 examples/modbusmaster/mbmaster_main.c diff --git a/examples/modbusmaster/.gitignore b/examples/modbusmaster/.gitignore new file mode 100644 index 000000000..fa1ec7579 --- /dev/null +++ b/examples/modbusmaster/.gitignore @@ -0,0 +1,11 @@ +/Make.dep +/.depend +/.built +/*.asm +/*.obj +/*.rel +/*.lst +/*.sym +/*.adb +/*.lib +/*.src diff --git a/examples/modbusmaster/Kconfig b/examples/modbusmaster/Kconfig new file mode 100644 index 000000000..ab071dd29 --- /dev/null +++ b/examples/modbusmaster/Kconfig @@ -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 diff --git a/examples/modbusmaster/Make.defs b/examples/modbusmaster/Make.defs new file mode 100644 index 000000000..f053ef510 --- /dev/null +++ b/examples/modbusmaster/Make.defs @@ -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 +# +# 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 diff --git a/examples/modbusmaster/Makefile b/examples/modbusmaster/Makefile new file mode 100644 index 000000000..184487950 --- /dev/null +++ b/examples/modbusmaster/Makefile @@ -0,0 +1,56 @@ +############################################################################ +# apps/examples/modbusmaster/Makefile +# +# Copyright (C) 2019 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt +# +# 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 diff --git a/examples/modbusmaster/mbmaster_main.c b/examples/modbusmaster/mbmaster_main.c new file mode 100644 index 000000000..fb77eda9f --- /dev/null +++ b/examples/modbusmaster/mbmaster_main.c @@ -0,0 +1,349 @@ +/**************************************************************************** + * apps/examples/modbusmaster/mbmaster_main.c + * + * Copyright (c) 2016 Vytautas Lukenskas + * Copyright (c) 2019 Alan Carvalho de Assis + * 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 +#include +#include +#include +#include +#include + +#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); +}