nuttx-apps/examples/modbusmaster/mbmaster_main.c

350 lines
9.8 KiB
C

/****************************************************************************
* 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 */
#ifndef CONFIG_SERIAL_TERMIOS
# error "CONFIG_SERIAL_TERMIOS is needed by modbus example"
#endif
#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 */
eMBMasterDisable();
/* Release hardware resources */
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
*
****************************************************************************/
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
****************************************************************************/
int main(int argc, FAR char *argv[])
{
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);
}