API  2.2
TSmarT Software Library
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
modbus_slave_rtu.c

This is a basic example of a ModBUS Slave RTU

/* @file modbus_slave_rtu.c
* @author TST
* @version 0.1
* @date 02/07/2012
* @brief This is an example about how to manage the stack modbus in slave mode.
*/
/* Platform headers */
#include "tsmart.h"
/* Modbus headers */
#include "modbus/port/mbport.h"
#include "modbus/mbslave/include/mbs.h"
#include "modbus/common/include/mbframe.h"
#include "modbus/common/include/mbportlayer.h"
#include "modbus/common/include/mbutils.h"
/* ----------------------- Defines ------------------------------------------*/
#define MB_RTU_SLAVE_ADDR ( 0x01 )
/* ----------------------- Static variables ---------------------------------*/
static xMBSHandle MBSHandle;
//STATIC USHORT usRegInputValue[16];
STATIC USHORT usRegHoldingValue[16];
/* *************************************************************************************************************** */
/* Modbus Handlers */
/* *************************************************************************************************************** */
eMBException eMyRegCoilCB(UBYTE * pubRegBuffer, USHORT usAddress, USHORT usNRegs, eMBSRegisterMode eRegMode) {
/* Only one coil may be accessed at this moment */
if (usNRegs != 1) {
return MB_PDU_EX_ILLEGAL_DATA_ADDRESS;
}
/* Map address to pin */
switch (usAddress) {
case 0x0000:
dio = tsmart_dio0a;
break;
case 0x0001:
dio = tsmart_dio1a;
break;
case 0x0002:
dio = tsmart_dio7;
break;
default:
return MB_PDU_EX_ILLEGAL_DATA_ADDRESS;
}
/* Read or write */
switch (eRegMode) {
if (pubRegBuffer[0] == 0) {
/* Write coil value */
}
else {
/* Write coil value */
}
break;
/* Read coil value */
pubRegBuffer[0] = TSMART_DIO_Read(&dio);
break;
default:
return MB_PDU_EX_ILLEGAL_DATA_VALUE;
}
return MB_PDU_EX_NONE;
}
eMBException eMyDiscreteInputCB(UBYTE *pubRegBuffer, USHORT usAddress, USHORT usNRegs) {
eMBException eException = MB_PDU_EX_NONE;
return eException;
}
eMBException eMyRegInputCB(UBYTE * pubRegBuffer, USHORT usAddress, USHORT usNRegs) {
uint16_t value;
uint8_t i;
uint8_t text[30]="ESTO ES UN TEXTO \r\n";
memset (text,0x00,sizeof(text));
sprintf(text,"ESTO ES UN TEXTO \r\n");
/* Map address to ADC */
switch (usAddress) {
case 0x0000:
/* AI0 */
/* Only one register may be accessed at this moment */
if (usNRegs != 1) {
return MB_PDU_EX_ILLEGAL_DATA_ADDRESS;
}
break;
case 0x0001:
/* AI1 */
/* Only one register may be accessed at this moment */
if (usNRegs != 1) {
return MB_PDU_EX_ILLEGAL_DATA_ADDRESS;
}
break;
case 0x0002:
/* TEXT */
if (usNRegs > 15) { /* Read 15 --> 15 uint16 = 30 uint8 or 30 char */
return MB_PDU_EX_ILLEGAL_DATA_ADDRESS;
}
for (i=0;i<=usNRegs;i=i+2){
*pubRegBuffer++ = text[i+1];
*pubRegBuffer++ = text[i];
}
return MB_PDU_EX_NONE;
break;
default:
return MB_PDU_EX_ILLEGAL_DATA_ADDRESS;
}
value = TSMART_AI_Read(&ai);
*pubRegBuffer++ = (UBYTE)(value >> 8 );
*pubRegBuffer++ = (UBYTE)(value & 0xFF);
return MB_PDU_EX_NONE;
}
eMBException eMyRegHoldingCB(UBYTE * pubRegBuffer, USHORT usAddress, USHORT usNRegs, eMBSRegisterMode eRegMode) {
eMBException eException = MB_PDU_EX_ILLEGAL_DATA_ADDRESS;
STATIC const ULONG usRegsMappedAt = 0x0000;
ULONG usRegStart = usAddress;
ULONG usRegEnd = usAddress + usNRegs - 1;
USHORT usIndex;
USHORT usIndexEnd;
if ((usNRegs > 0) &&
(usRegStart >= usRegsMappedAt) &&
(usRegEnd <= (usRegsMappedAt + MB_UTILS_NARRSIZE(usRegHoldingValue))))
{
usIndex = ( USHORT ) ( usRegStart - usRegsMappedAt );
usIndexEnd = ( USHORT ) ( usRegEnd - usRegsMappedAt );
switch ( eRegMode )
{
for( ; usIndex <= usIndexEnd; usIndex++ )
{
usRegHoldingValue[usIndex] = ( USHORT ) * pubRegBuffer++ << 8;
usRegHoldingValue[usIndex] |= ( USHORT ) * pubRegBuffer++;
}
break;
default:
for( ; usIndex <= usIndexEnd; usIndex++ )
{
*pubRegBuffer++ = ( UBYTE ) ( usRegHoldingValue[usIndex] >> 8 );
*pubRegBuffer++ = ( UBYTE ) ( usRegHoldingValue[usIndex] & 0xFF );
}
break;
}
eException = MB_PDU_EX_NONE;
}
return eException;
}
/* @brief ModBUS RTU handler task
*
* This task initializes the ModBUS serial stack, registers the callbacks and
* polls the stack for incoming requests.
*
* @param pvParameters Not used
*/
static void MBRTUTask(void *pvParameters) {
static uint8_t data[32];
eMBErrorCode eStatus;
/* Coil handler */
if (MB_ENOERR != eMBSRegisterCoilCB(MBSHandle, eMyRegCoilCB)) {
for(;;);
}
/* Discrete input */
if (MB_ENOERR != eMBSRegisterDiscreteCB(MBSHandle, eMyDiscreteInputCB)) {
for(;;);
}
/* Input Register handler */
if (MB_ENOERR != eMBSRegisterInputCB(MBSHandle, eMyRegInputCB)) {
for(;;);
}
/* Holding Register handler */
if (MB_ENOERR != eMBSRegisterHoldingCB(MBSHandle, eMyRegHoldingCB)) {
for(;;);
}
/* Main loop */
for (;;) {
/* Poll the communication stack. */
eStatus = eMBSPoll(MBSHandle);
if (eStatus != MB_ENOERR) {
break;
}
}
/* We have exited BodBus main loop */
if (MB_ENOERR != eMBSClose(MBSHandle)) {
for(;;);
}
for(;;);
}
/* @brief "Init()" function.
*
* This is the first thing that the user must do for using TSmarT.
* It initializes specific hardware resources (GPRS, GPS, AI, DIO, MODBUS, MSA...)
* and software resources (queues, mutex, tasks...) for the user application.
*
* The way to fill in this function properly is to initialize first
* hardware resources and after that software resources.
*
* This function must return: TSMART_PASS when every thing is OK or
* TSMART_FAIL when a failure happened.
*
* @return
* @arg TSMART_PASS
* @arg TSMART_FAIL
*/
int32_t init() {
/* Variables */
portBASE_TYPE xReturn;
tsmart_dio_config_t tsmart_dio_config;
tsmart_ai_config_t tsmart_ai_config;
/* ************************************************************************* */
/* Debug Mode */
/* ************************************************************************* */
/* ************************************************************************* */
/* Initialize resources */
/* ************************************************************************* */
/* DIO configuration. User needs to configure the DIO to connect a LED */
tsmart_dio_config.mode = TSMART_DIO_OD;
tsmart_dio_config.irq_mode = TSMART_DIO_IRQ_NULL;
/* Initialize DIOs
* User must initialize the DIOs to use. In this example one for reading a value and another one for
* connecting a LED */
TSMART_DIO_Init(&tsmart_dio0a, &tsmart_dio_config);
TSMART_DIO_Init(&tsmart_dio1a, &tsmart_dio_config);
TSMART_DIO_Init(&tsmart_dio7, &tsmart_dio_config);
/* Set Analog Input (AI) configuration (ADC configuration is needed to use the AI).
* User needs to configure the Analog Digital Converter (ADC) with the desire values */
tsmart_ai_config.ai_mode = TSMART_AI_MODE_INDEPENDENT;
tsmart_ai_config.ai_scan_conv_mode = DISABLE;
tsmart_ai_config.ai_continuous_conv_mode = DISABLE;
tsmart_ai_config.ai_data_align = TSMART_AI_DATAALIGN_RIGHT;
tsmart_ai_config.ai_sample_time = TSMART_AI_SAMPLETIME_41CYCLES5;
tsmart_ai_config.adc = TSMART_AI_ADC1;
/* Initialize Analog Input (AI) user is going to use. In this example ai0a is initialized */
TSMART_AI_Init(&tsmart_ai2a, &tsmart_ai_config);
TSMART_AI_Init(&tsmart_ai3a, &tsmart_ai_config);
/* ************************************************************************* */
/* Application task */
/* ************************************************************************* */
/* This examples will need these:
*
* - MBRTUTask task.
* - Initialize Modbus stack
* - Initialize communication interface: RS-485
*
*/
/* Initialize ModBus porting */
if (vMBPInit() != 0) {
return TSMART_FAIL;
}
/* Initialize the Slave RTU */
if (eMBSSerialInit(&MBSHandle, MB_RTU, MB_RTU_SLAVE_ADDR, 0, 9600, MB_PAR_NONE) != MB_ENOERR) {
return TSMART_FAIL;
}
/* Create the ModBus TCP server task */
xReturn = xTaskCreate(MBRTUTask, "MODBUS", 512, NULL, 1, NULL);
if (xReturn != pdPASS) {
return TSMART_FAIL;
}
return TSMART_PASS;
}