Commit 7c5b1249 authored by Claes Sjofors's avatar Claes Sjofors

Modbus RTU added

parent e431ce45
/*
* Proview Open Source Process Control.
* Copyright (C) 2005-2011 SSAB Oxelosund AB.
*
* This file is part of Proview.
*
* 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 Proview. If not, see <http://www.gnu.org/licenses/>
*
* Linking Proview statically or dynamically with other modules is
* making a combined work based on Proview. Thus, the terms and
* conditions of the GNU General Public License cover the whole
* combination.
*
* In addition, as a special exception, the copyright holders of
* Proview give you permission to, from the build function in the
* Proview Configurator, combine Proview with modules generated by the
* Proview PLC Editor to a PLC program, regardless of the license
* terms of these modules. You may copy and distribute the resulting
* combined work under the terms of your choice, provided that every
* copy of the combined work is accompanied by a complete copy of
* the source code of Proview (the version used to produce the
* combined work), being distributed under the terms of the GNU
* General Public License plus this exception.
*/
/* rt_io_m_mb_rtu_master.c -- io methods for the Modbus RTU Master object
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#if defined OS_LINUX
#include <termio.h>
#endif
#if defined OS_LINUX || defined OS_MACOS
#include <sgtty.h>
#endif
#include <sys/ioctl.h>
#include "pwr.h"
#include "co_cdh.h"
#include "pwr_baseclasses.h"
#include "pwr_basecomponentclasses.h"
#include "pwr_otherioclasses.h"
#include "rt_gdh.h"
#include "rt_io_base.h"
#include "rt_io_bus.h"
#include "rt_io_msg.h"
#include "rt_errh.h"
#include "co_cdh.h"
#include "co_time.h"
#include "rt_mb_msg.h"
#include "rt_io_mb_rtu.h"
#include "rt_io_agent_init.h"
char rcv_buffer[65536];
static pwr_tStatus IoAgentInit (
io_tCtx ctx,
io_sAgent *ap
);
static pwr_tStatus IoAgentRead (
io_tCtx ctx,
io_sAgent *ap
);
static pwr_tStatus IoAgentWrite (
io_tCtx ctx,
io_sAgent *ap
);
static pwr_tStatus IoAgentClose (
io_tCtx ctx,
io_sAgent *ap
);
static void float_to_timeval(struct timeval *tv, float t)
{
tv->tv_sec = t;
tv->tv_usec = (t-(float)tv->tv_sec) * 1000000;
}
static void float_to_timespec(struct timespec *tv, float t)
{
tv->tv_sec = t;
tv->tv_nsec = (t-(float)tv->tv_sec) * 1000000000;
}
/*----------------------------------------------------------------------------*\
Init method for the Modbus RTU Master agent
\*----------------------------------------------------------------------------*/
static pwr_tStatus IoAgentInit (
io_tCtx ctx,
io_sAgent *ap
)
{
struct termios tty_attributes;
int sts;
io_sAgentLocal *local;
pwr_sClass_Modbus_RTU_Master *op = (pwr_sClass_Modbus_RTU_Master *)ap->op;
/* Allocate area for local data structure */
ap->Local = calloc(1, sizeof(io_sAgentLocal));
local = ap->Local;
local->fd = open( op->Device, O_RDWR | O_NDELAY | O_NOCTTY);
if ( local->fd == -1) {
errh_Error( "Modbus RTU Master, open device error, %s", ap->Name);
return IO__ERRINIDEVICE;
}
tcgetattr( local->fd, &tty_attributes);
tty_attributes.c_cc[VMIN] = 1;
tty_attributes.c_cc[VTIME] = 0;
tty_attributes.c_lflag &= ~(ICANON | ISIG | ECHO | IEXTEN);
tty_attributes.c_cflag |= (CLOCAL | CREAD);
tty_attributes.c_oflag &= ~(OPOST);
tty_attributes.c_oflag &= ~(ONLCR);
tty_attributes.c_iflag &= ~(INLCR | ICRNL);
/* Speed */
#if defined OS_LINUX
tty_attributes.c_cflag &= ~CBAUD;
#endif
switch( op->Speed) {
case 300:
tty_attributes.c_cflag |= B300;
break;
case 1200:
tty_attributes.c_cflag |= B1200;
break;
case 2400:
tty_attributes.c_cflag |= B2400;
break;
case 4800:
tty_attributes.c_cflag |= B4800;
break;
case 9600:
tty_attributes.c_cflag |= B9600;
break;
case 19200:
tty_attributes.c_cflag |= B19200;
break;
default:
errh_Error( "Modbus RTU Master, unsupported speed, %s", ap->Name);
tty_attributes.c_cflag |= B9600;
break;
}
/* DataBits 5, 6, 7 or 8 */
tty_attributes.c_cflag &= ~CSIZE;
switch ( op->DataBits) {
case pwr_eDataBitsEnum_5:
tty_attributes.c_cflag |= CS5;
break;
case pwr_eDataBitsEnum_6:
tty_attributes.c_cflag |= CS6;
break;
case pwr_eDataBitsEnum_7:
tty_attributes.c_cflag |= CS7;
break;
case pwr_eDataBitsEnum_8:
tty_attributes.c_cflag |= CS8;
break;
default:
errh_Error( "Modbus RTU Master, unsupported DataBits, %s", ap->Name);
tty_attributes.c_cflag |= CS8;
}
//tty_attributes.c_iflag |=ISTRIP;
/* Parity */
switch ( op->Parity) {
case pwr_eParityEnum_Odd:
case pwr_eParityEnum_Even:
tty_attributes.c_cflag |= PARENB;
tty_attributes.c_iflag |= IGNPAR;
if ( op->Parity == pwr_eParityEnum_Even)
tty_attributes.c_cflag &= ~PARODD;
else
tty_attributes.c_cflag |= PARODD;
break;
default:
tty_attributes.c_cflag &= ~PARENB;
}
/* stopbitsval */
switch ( op->StopBits) {
case pwr_eStopBitsEnum_2:
tty_attributes.c_cflag |=CSTOPB;
break;
case pwr_eStopBitsEnum_1:
tty_attributes.c_cflag &=~CSTOPB;
break;
case pwr_eStopBitsEnum_0:
errh_Error( "Modbus RTU Master, unsupported StopBits, %s", ap->Name);
tty_attributes.c_cflag &=~CSTOPB;
break;
}
tty_attributes.c_iflag &= ~IXON; //ingen XON/XOFF in
//tty_attributes.c_iflag &= (V_IGNCR);
//tty_attributes.c_iflag &= (IGNPAR | V_IGNCR);
//tty_attributes.c_iflag &= ~(BRKINT | IXON | V_INLCR | V_ICRNL);
//tty_attributes.c_cflag &= ~(CSIZE | CSTOPB | PARENB); //fippla om vrden lite granna
sts = tcsetattr( local->fd, TCSANOW, &tty_attributes);
if ( sts < 0) {
errh_Error( "Modbus RTU Master, set device attributes error, %s", ap->Name);
return IO__ERRINIDEVICE;
}
tcflush( local->fd, TCIOFLUSH);
// Test
sleep(2);
local->initialized = TRUE;
return IO__SUCCESS;
}
static void generate_crc( unsigned char *buf, int size, unsigned char *result)
{
unsigned short int crc;
unsigned short int gen_polynomial = 0xA001;
unsigned short int flag_mask = 0x0001;
unsigned short int flag;
int i, j;
crc = 0xFFFF;
for ( i = 0; i < size; i++) {
crc = crc^buf[i];
for ( j = 0; j < 8; j++) {
flag = crc & flag_mask;
crc = crc >> 1;
if ( flag)
crc = crc ^ gen_polynomial;
}
}
result[0] = (unsigned char) (crc & 0x00FF);
result[1] = (unsigned char) ((crc >> 8) & 0x00FF);
}
static pwr_tStatus rtu_send( io_sRack *rp,
io_sAgentLocal *local_master,
io_sRackLocal *local_slave,
io_sCardLocalMsg *local_card,
pwr_sClass_Modbus_RTU_Master *masterp,
pwr_sClass_Modbus_RTU_Slave *slavep,
pwr_sClass_Modbus_RTU_Module *modulep,
unsigned char *buf,
int buffer_size)
{
int sts;
rec_buf *rb;
unsigned char fc;
int data_size = 0;
unsigned char telegram[512];
unsigned char crc[2];
fd_set read_fd;
struct timeval tv;
generate_crc( buf, buffer_size, &buf[buffer_size]);
if ( masterp->Debug) {
int i;
pwr_tTime current;
char timstr[40];
time_GetTime( &current);
time_AtoAscii( &current, time_eFormat_Time, timstr, sizeof(timstr));
printf( "Snd: %s %2d ", timstr, buffer_size + 2);
for ( i = 0; i < buffer_size + 2; i++)
printf( "%02d ", buf[i]);
printf( "\n");
}
sts = write( local_master->fd, buf, buffer_size + 2);
if (sts <= 0) {
slavep->ErrorCount++;
return 0;
}
slavep->TX_packets++;
/* Receive answer */
sts = 1;
float_to_timeval( &tv, masterp->ReceiveTimeout);
FD_ZERO(&read_fd);
FD_SET( local_master->fd, &read_fd);
sts = select( local_master->fd + 1, &read_fd, NULL, NULL, &tv);
if ( sts == 0)
return 0;
sts = read( local_master->fd, telegram, 1);
if (sts <= 0) {
if ( masterp->Debug)
printf( "Rcv: Nothing to read\n");
return 0;
}
while( sts > 0) {
data_size++;
float_to_timeval( &tv, masterp->CharTimeout);
FD_ZERO( &read_fd);
FD_SET( local_master->fd, &read_fd);
sts = select( local_master->fd + 1, &read_fd, NULL, NULL, &tv);
if ( sts == 0) {
break;
}
sts = read( local_master->fd, telegram + data_size, 1);
}
if ( data_size < 2) {
if ( masterp->Debug)
printf( "Rcv: Data size < 2\n");
return 0;
}
if ( masterp->Debug) {
int i;
pwr_tTime current;
char timstr[40];
time_GetTime( &current);
time_AtoAscii( &current, time_eFormat_Time, timstr, sizeof(timstr));
printf( "Rcv: %s %2d ", timstr, data_size);
for ( i = 0; i < data_size; i++)
printf( "%02d ", telegram[i]);
printf( "\n");
}
generate_crc( telegram, data_size - 2, crc);
if ( crc[0] != telegram[data_size-2] || crc[1] != telegram[data_size-1]) {
slavep->ErrorCount++;
return 0;
}
slavep->RX_packets++;
rb = (rec_buf *) telegram;
fc = rb->fc;
if (fc != modulep->FunctionCode) {
return 0;
}
slavep->Status = MB__NORMAL;
modulep->Status = pwr_eModbusModule_StatusEnum_OK;
switch (fc) {
case pwr_eModbus_FCEnum_ReadCoils: {
res_read *res_r;
res_r = (res_read *) rb;
memcpy(local_card->input_area, res_r->buf, MIN(res_r->bc, local_card->input_size));
break;
}
case pwr_eModbus_FCEnum_ReadDiscreteInputs: {
res_read *res_r;
res_r = (res_read *) rb;
memcpy(local_card->input_area, res_r->buf, MIN(res_r->bc, local_card->input_size));
break;
}
case pwr_eModbus_FCEnum_ReadHoldingRegisters: {
res_read *res_r;
res_r = (res_read *) rb;
memcpy(local_card->input_area, res_r->buf, MIN(res_r->bc, local_card->input_size));
break;
}
case pwr_eModbus_FCEnum_ReadInputRegisters: {
res_read *res_r;
res_r = (res_read *) rb;
memcpy(local_card->input_area, res_r->buf, MIN(res_r->bc, local_card->input_size));
break;
}
case pwr_eModbus_FCEnum_WriteMultipleCoils:
case pwr_eModbus_FCEnum_WriteMultipleRegisters:
case pwr_eModbus_FCEnum_WriteSingleRegister:
// Nothing good to do here
break;
}
return IO__SUCCESS;
}
static pwr_tStatus mb_rtu_send_data( io_sRack *rp,
io_sAgentLocal *local_master,
io_sRackLocal *local_slave,
pwr_sClass_Modbus_RTU_Master *masterp,
pwr_sClass_Modbus_RTU_Slave *slavep,
mb_tSendMask mask)
{
io_sCardLocalMsg *local_card;
io_sCard *cardp;
pwr_sClass_Modbus_RTU_Module *modulep;
pwr_tStatus sts;
pwr_tCid cid;
int modules;
int i;
int send_error;
struct timespec tf;
/* Send messages to slave */
cardp = rp->cardlist;
while(cardp) {
cid = cardp->Class;
while ( ODD( gdh_GetSuperClass( cid, &cid, cardp->Objid))) ;
switch (cid) {
case pwr_cClass_Modbus_RTU_Module:
modulep = (pwr_sClass_Modbus_RTU_Module *) cardp->op;
modules = 1;
break;
default:
modules = 0;
}
if ( !modules) {
cardp = cardp->next;
continue;
}
send_error = 0;
for ( i = 0; i < modules; i++) {
sts = 1;
if (!modulep->Continous && !modulep->SendOp) {
break;
}
local_card = &((io_sCardLocal *)cardp->Local)->msg[i];
if ( modulep->ScanInterval > 1 && local_card->interval_cnt != 0) {
modulep++;
continue;
}
if (mask & mb_mSendMask_ReadReq) {
switch (modulep->FunctionCode) {
case pwr_eModbus_FCEnum_ReadCoils:
case pwr_eModbus_FCEnum_ReadDiscreteInputs: {
read_req rr;
modulep->SendOp = FALSE;
rr.unit_id = modulep->UnitId;
rr.fc = modulep->FunctionCode;
rr.addr = htons(modulep->Address);
rr.quant = htons(local_card->no_di);
// rr.quant = ntohs(local_card->input_size * 8);
sts = rtu_send( rp, local_master, local_slave, local_card,
masterp, slavep, modulep, (unsigned char *)&rr, sizeof(read_req)-2);
if ( EVEN(sts)) {
slavep->Status = MB__CONNDOWN;
slavep->ErrorCount++;
send_error = 1;
break;
}
slavep->Status = MB__NORMAL;
break;
}
case pwr_eModbus_FCEnum_ReadHoldingRegisters:
case pwr_eModbus_FCEnum_ReadInputRegisters: {
read_req rr;
modulep->SendOp = FALSE;
rr.unit_id = modulep->UnitId;
rr.fc = modulep->FunctionCode;
rr.addr = htons(modulep->Address);
rr.quant = ntohs((local_card->input_size + 1) / 2);
sts = rtu_send( rp, local_master, local_slave, local_card,
masterp, slavep, modulep, (unsigned char *)&rr, sizeof(read_req)-2);
if ( EVEN(sts)) {
slavep->Status = MB__CONNDOWN;
slavep->ErrorCount++;
send_error = 1;
break;
}
slavep->Status = MB__NORMAL;
break;
}
} /* End - switch FC ... */
}
if (mask & mb_mSendMask_WriteReq) {
switch (modulep->FunctionCode) {
case pwr_eModbus_FCEnum_WriteSingleCoil: {
write_single_req wsr;
modulep->SendOp = FALSE;
wsr.unit_id = modulep->UnitId;
wsr.fc = modulep->FunctionCode;
wsr.addr = htons(modulep->Address);
if (local_card->output_size == 4) {
if (*(int *)local_card->output_area)
wsr.value = ntohs(0xFF00);
else wsr.value = 0;
} else if (local_card->output_size == 2) {
if (*(short int *)local_card->output_area)
wsr.value = ntohs(0xFF00);
else wsr.value = 0;
} else if (local_card->output_size == 1) {
if (*(char *)local_card->output_area)
wsr.value = ntohs(0xFF00);
else wsr.value = 0;
} else wsr.value = 0;
sts = rtu_send( rp, local_master, local_slave, local_card,
masterp, slavep, modulep, (unsigned char *)&wsr, sizeof(wsr) - 2);
if ( EVEN(sts)) {
slavep->Status = MB__CONNDOWN;
slavep->ErrorCount++;
send_error = 1;
break;
}
slavep->Status = MB__NORMAL;
break;
}
case pwr_eModbus_FCEnum_WriteMultipleCoils: {
write_coils_req wcr;
modulep->SendOp = FALSE;
wcr.unit_id = modulep->UnitId;
wcr.fc = modulep->FunctionCode;
wcr.addr = htons(modulep->Address);
wcr.quant = htons(local_card->no_do);
// wcr.quant = ntohs((local_card->output_size) * 8);
wcr.bc = local_card->output_size;
memcpy(wcr.reg, local_card->output_area, local_card->output_size);
sts = rtu_send( rp, local_master, local_slave, local_card,
masterp, slavep, modulep, (unsigned char *)&wcr,
sizeof(wcr) - 2 - sizeof(wcr.reg) + local_card->output_size);
if ( EVEN(sts)) {
slavep->Status = MB__CONNDOWN;
slavep->ErrorCount++;
send_error = 1;
break;
}
slavep->Status = MB__NORMAL;
break;
}
case pwr_eModbus_FCEnum_WriteMultipleRegisters: {
write_reg_req wrr;
modulep->SendOp = FALSE;
wrr.unit_id = modulep->UnitId;
wrr.fc = modulep->FunctionCode;
wrr.addr = htons(modulep->Address);
wrr.quant = ntohs((local_card->output_size) / 2);
wrr.bc = local_card->output_size;
memcpy(wrr.reg, local_card->output_area, local_card->output_size);
sts = rtu_send( rp, local_master, local_slave, local_card,
masterp, slavep, modulep, (unsigned char *)&wrr,
sizeof(wrr) - 2 - sizeof(wrr.reg) + local_card->output_size);
if ( EVEN(sts)) {
slavep->Status = MB__CONNDOWN;
slavep->ErrorCount++;
send_error = 1;
break;
}
slavep->Status = MB__NORMAL;
break;
}
case pwr_eModbus_FCEnum_WriteSingleRegister: {
write_single_req wrr;
modulep->SendOp = FALSE;
wrr.unit_id = modulep->UnitId;
wrr.fc = modulep->FunctionCode;
wrr.addr = htons(modulep->Address);
memcpy(&wrr.value, local_card->output_area, sizeof(wrr.value));
sts = rtu_send( rp, local_master, local_slave, local_card,
masterp, slavep, modulep, (unsigned char *)&wrr, sizeof(wrr) - 2);
if ( EVEN(sts)) {
slavep->Status = MB__CONNDOWN;
slavep->ErrorCount++;
send_error = 1;
break;
}
slavep->Status = MB__NORMAL;
break;
}
} /* End - switch FC ... */
}
if ( send_error && cardp->next) {
/* Time to next frame */
float_to_timespec( &tf, masterp->FrameTimeout - masterp->CharTimeout);
nanosleep( &tf, NULL);
break;
}
if ( !(i == modules - 1 && !cardp->next)) {
float_to_timespec( &tf, masterp->FrameTimeout - masterp->CharTimeout);
nanosleep( &tf, NULL);
}
modulep++;
}
cardp = cardp->next;
} /* End - while cardp ... */
return IO__SUCCESS;
}
/*----------------------------------------------------------------------------*\
Read method for the Modbus RTU Master agent
\*----------------------------------------------------------------------------*/
static pwr_tStatus IoAgentRead (
io_tCtx ctx,
io_sAgent *ap
)
{
io_sAgentLocal *local;
io_sRackLocal *local_rack;
pwr_tUInt16 sts;
io_sRack *rp;
pwr_tCid cid;
pwr_sClass_Modbus_RTU_Slave *sp;
pwr_sClass_Modbus_RTU_Master *op = (pwr_sClass_Modbus_RTU_Master *)ap->op;
local = (io_sAgentLocal *) ap->Local;
rp = ap->racklist;
while ( rp) {
cid = rp->Class;
while ( ODD( gdh_GetSuperClass( cid, &cid, rp->Objid))) ;
switch (cid) {
case pwr_cClass_Modbus_RTU_Slave:
sp = (pwr_sClass_Modbus_RTU_Slave *) rp->op;
local_rack = rp->Local;
/* Request new data */
if ( /* sp->Status == MB__NORMAL && */ sp->DisableSlave != 1) {
sts = mb_rtu_send_data( rp, local, local_rack, op, sp, mb_mSendMask_ReadReq);
if ( sp->ErrorCount >= sp->ErrorLimit) {
switch ( sp->StallAction) {
case pwr_eStallActionEnum_EmergencyBreak:
ctx->Node->EmergBreakTrue = 1;
break;
case pwr_eStallActionEnum_ResetInputs:
memset( sp->Inputs, 0, local_rack->input_size);
local_rack->reset_inputs = 1;
break;
default: ;
}
}
else
local_rack->reset_inputs = 0;
}
break;
}
rp = rp->next;
}
return IO__SUCCESS;
}
/*----------------------------------------------------------------------------*\
Write method for the Modbus RTU Master agent
\*----------------------------------------------------------------------------*/
static pwr_tStatus IoAgentWrite (
io_tCtx ctx,
io_sAgent *ap
)
{
io_sAgentLocal *local;
io_sRackLocal *local_rack;
pwr_tUInt16 sts;
io_sRack *rp;
pwr_tCid cid;
pwr_sClass_Modbus_RTU_Slave *sp;
pwr_sClass_Modbus_RTU_Master *op = (pwr_sClass_Modbus_RTU_Master *)ap->op;
local = (io_sAgentLocal *) ap->Local;
rp = ap->racklist;
while ( rp) {
cid = rp->Class;
while ( ODD( gdh_GetSuperClass( cid, &cid, rp->Objid))) ;
switch (cid) {
case pwr_cClass_Modbus_RTU_Slave:
sp = (pwr_sClass_Modbus_RTU_Slave *) rp->op;
local_rack = rp->Local;
/* Request new data */
if ( /* sp->Status == MB__NORMAL && */ sp->DisableSlave != 1) {
sts = mb_rtu_send_data( rp, local, local_rack, op, sp, mb_mSendMask_WriteReq);
}
break;
}
rp = rp->next;
}
return IO__SUCCESS;
}
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
static pwr_tStatus IoAgentClose (
io_tCtx ctx,
io_sAgent *ap
)
{
io_sAgentLocal *local = (io_sAgentLocal *) ap->Local;
close( local->fd);
return IO__SUCCESS;
}
/*----------------------------------------------------------------------------*\
Every method to be exported to the workbench should be registred here.
\*----------------------------------------------------------------------------*/
pwr_dExport pwr_BindIoMethods(Modbus_RTU_Master) = {
pwr_BindIoMethod(IoAgentInit),
pwr_BindIoMethod(IoAgentRead),
pwr_BindIoMethod(IoAgentWrite),
pwr_BindIoMethod(IoAgentClose),
pwr_NullMethod
};
/*
* Proview Open Source Process Control.
* Copyright (C) 2005-2011 SSAB Oxelosund AB.
*
* This file is part of Proview.
*
* 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 Proview. If not, see <http://www.gnu.org/licenses/>
*
* Linking Proview statically or dynamically with other modules is
* making a combined work based on Proview. Thus, the terms and
* conditions of the GNU General Public License cover the whole
* combination.
*
* In addition, as a special exception, the copyright holders of
* Proview give you permission to, from the build function in the
* Proview Configurator, combine Proview with modules generated by the
* Proview PLC Editor to a PLC program, regardless of the license
* terms of these modules. You may copy and distribute the resulting
* combined work under the terms of your choice, provided that every
* copy of the combined work is accompanied by a complete copy of
* the source code of Proview (the version used to produce the
* combined work), being distributed under the terms of the GNU
* General Public License plus this exception.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <math.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include "pwr.h"
#include "pwr_baseclasses.h"
#include "pwr_basecomponentclasses.h"
#include "pwr_otherioclasses.h"
#include "rt_io_base.h"
#include "rt_io_msg.h"
#include "rt_errh.h"
#include "rt_io_bus.h"
#include "rt_mb_msg.h"
#include "rt_io_mb_rtu.h"
/*----------------------------------------------------------------------------*\
Init method for the Modbus module
\*----------------------------------------------------------------------------*/
static pwr_tStatus IoCardInit (
io_tCtx ctx,
io_sAgent *ap,
io_sRack *rp,
io_sCard *cp
)
{
io_sCardLocalMsg *local;
pwr_sClass_Modbus_RTU_Module *op;
int i;
op = (pwr_sClass_Modbus_RTU_Module *) cp->op;
local = ((io_sCardLocal *) cp->Local)->msg;
for (i = 0; i < IO_MAXCHAN; i++) {
local->scancount[i] = 0;
}
op->Status = pwr_eModbusModule_StatusEnum_StatusUnknown;
return IO__SUCCESS;
}
/*----------------------------------------------------------------------------*\
Read method for the Modbus RTU module
\*----------------------------------------------------------------------------*/
static pwr_tStatus IoCardRead (
io_tCtx ctx,
io_sAgent *ap,
io_sRack *rp,
io_sCard *cp
)
{
io_sCardLocalMsg *local;
io_sRackLocal *local_rack = (io_sRackLocal *)rp->Local;
pwr_sClass_Modbus_RTU_Module *op;
pwr_sClass_Modbus_RTU_Slave *slave;
op = (pwr_sClass_Modbus_RTU_Module *) cp->op;
local = ((io_sCardLocal *) cp->Local)->msg;
slave = (pwr_sClass_Modbus_RTU_Slave *) rp->op;
if ( op->ScanInterval > 1) {
local->has_read_method = 1;
if ( local->interval_cnt != 0) {
local->interval_cnt++;
if ( local->interval_cnt >= op->ScanInterval)
local->interval_cnt = 0;
return IO__SUCCESS;
}
local->interval_cnt++;
}
if (slave->Status == MB__NORMAL || local_rack->reset_inputs) {
io_bus_card_read(ctx, rp, cp, slave->Inputs, NULL, pwr_eByteOrderingEnum_BigEndian, pwr_eFloatRepEnum_FloatIntel);
}
// printf("Method Modbus_RTU_Module-IoCardRead\n");
return IO__SUCCESS;
}
/*----------------------------------------------------------------------------*\
Write method for the Modbus RTU module
\*----------------------------------------------------------------------------*/
static pwr_tStatus IoCardWrite (
io_tCtx ctx,
io_sAgent *ap,
io_sRack *rp,
io_sCard *cp
)
{
io_sCardLocalMsg *local;
pwr_sClass_Modbus_RTU_Module *op;
pwr_sClass_Modbus_RTU_Slave *slave;
op = (pwr_sClass_Modbus_RTU_Module *) cp->op;
local = ((io_sCardLocal *) cp->Local)->msg;
slave = (pwr_sClass_Modbus_RTU_Slave *) rp->op;
if ( op->ScanInterval > 1) {
if ( !local->has_read_method) {
if ( local->interval_cnt != 0) {
local->interval_cnt++;
if ( local->interval_cnt >= op->ScanInterval)
local->interval_cnt = 0;
return IO__SUCCESS;
}
local->interval_cnt++;
}
else if ( local->interval_cnt != 1)
return IO__SUCCESS;
}
if (slave->Status == MB__NORMAL) {
io_bus_card_write(ctx, cp, slave->Outputs, pwr_eByteOrderingEnum_BigEndian, pwr_eFloatRepEnum_FloatIntel);
}
// printf("Method Modbus_RTU_Module-IoCardWrite\n");
return IO__SUCCESS;
}
/*----------------------------------------------------------------------------*\
Every method to be exported to the workbench should be registred here.
\*----------------------------------------------------------------------------*/
pwr_dExport pwr_BindIoMethods(Modbus_RTU_Module) = {
pwr_BindIoMethod(IoCardInit),
pwr_BindIoMethod(IoCardRead),
pwr_BindIoMethod(IoCardWrite),
pwr_NullMethod
};
/*
* Proview Open Source Process Control.
* Copyright (C) 2005-2011 SSAB Oxelosund AB.
*
* This file is part of Proview.
*
* 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 Proview. If not, see <http://www.gnu.org/licenses/>
*
* Linking Proview statically or dynamically with other modules is
* making a combined work based on Proview. Thus, the terms and
* conditions of the GNU General Public License cover the whole
* combination.
*
* In addition, as a special exception, the copyright holders of
* Proview give you permission to, from the build function in the
* Proview Configurator, combine Proview with modules generated by the
* Proview PLC Editor to a PLC program, regardless of the license
* terms of these modules. You may copy and distribute the resulting
* combined work under the terms of your choice, provided that every
* copy of the combined work is accompanied by a complete copy of
* the source code of Proview (the version used to produce the
* combined work), being distributed under the terms of the GNU
* General Public License plus this exception.
*/
/* rt_io_m_mb_rtu_server.c -- io methods for Modbus/RTU Server */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#if defined OS_LINUX
#include <termio.h>
#endif
#if defined OS_LINUX || defined OS_MACOS
#include <sgtty.h>
#endif
#include <sys/ioctl.h>
#include "pwr.h"
#include "co_cdh.h"
#include "pwr_baseclasses.h"
#include "pwr_basecomponentclasses.h"
#include "pwr_otherioclasses.h"
#include "pwr_version.h"
#include "rt_gdh.h"
#include "rt_io_base.h"
#include "rt_io_bus.h"
#include "rt_io_msg.h"
#include "rt_errh.h"
#include "co_cdh.h"
#include "co_time.h"
#include "rt_mb_msg.h"
#include "rt_io_mb_rtu.h"
char rcv_buffer[512];
static pwr_tStatus mb_init_channels( io_tCtx ctx, io_sAgent *ap, io_sRack *rp);
static void mb_shift_write( unsigned char *in, unsigned char *out, int sh, int quant);
static void mb_shift_read( unsigned char *in, unsigned char *out, int sh, int quant);
typedef struct {
io_sRack *rp;
} mb_sCondata;
static void float_to_timeval(struct timeval *tv, float t)
{
tv->tv_sec = t;
tv->tv_usec = (t-(float)tv->tv_sec) * 1000000;
}
static void float_to_timespec(struct timespec *tv, float t)
{
tv->tv_sec = t;
tv->tv_nsec = (t-(float)tv->tv_sec) * 1000000000;
}
static void generate_crc( unsigned char *buf, int size, unsigned char *result)
{
unsigned short int crc;
unsigned short int gen_polynomial = 0xA001;
unsigned short int flag_mask = 0x0001;
unsigned short int flag;
int i, j;
crc = 0xFFFF;
for ( i = 0; i < size; i++) {
crc = crc^buf[i];
for ( j = 0; j < 8; j++) {
flag = crc & flag_mask;
crc = crc >> 1;
if ( flag)
crc = crc ^ gen_polynomial;
}
}
result[0] = (unsigned char) (crc & 0x00FF);
result[1] = (unsigned char) ((crc >> 8) & 0x00FF);
}
static pwr_tStatus rtu_send( io_sServerLocal *local_master,
pwr_sClass_Modbus_RTU_Server *op,
void *bufp,
int buffer_size)
{
int sts;
unsigned char *buf = (unsigned char *)bufp;
struct timespec tf;
generate_crc( buf, buffer_size, &buf[buffer_size]);
if ( op->Debug) {
int i;
pwr_tTime current;
char timstr[40];
time_GetTime( &current);
time_AtoAscii( &current, time_eFormat_Time, timstr, sizeof(timstr));
printf( "Snd: %s %2d ", timstr, buffer_size + 2);
for ( i = 0; i < buffer_size + 2; i++)
printf( "%02d ", buf[i]);
printf( "\n");
}
float_to_timespec( &tf, op->FrameTimeout);
nanosleep( &tf, NULL);
sts = write( local_master->fd, buf, buffer_size + 2);
if (sts <= 0) {
op->ErrorCount++;
return 0;
}
return 1;
}
static void *mb_receive( void *data)
{
io_sRack *rp = ((mb_sCondata *)data)->rp;
io_sServerLocal* local_master = rp->Local;
pwr_sClass_Modbus_RTU_Server *op = (pwr_sClass_Modbus_RTU_Server *) rp->op;
int data_size = 0;
rec_buf *rb;
unsigned char fc;
unsigned char exception_code;
ssize_t ssts;
struct timeval tv = {0,0};
int sts;
fd_set read_fd;
unsigned char crc[2];
unsigned char telegram[512];
free( data);
tcflush( local_master->fd, TCIOFLUSH);
while ( 1) {
sts = 1;
data_size = 0;
float_to_timeval( &tv, op->CharTimeout);
FD_ZERO(&read_fd);
FD_SET( local_master->fd, &read_fd);
sts = select( local_master->fd + 1, &read_fd, NULL, NULL, &tv);
if ( sts == 0)
continue;
sts = read( local_master->fd, telegram, 1);
if (sts <= 0) {
op->Status = MB__CONNLOST;
continue;
}
while( sts > 0) {
data_size++;
if ( data_size > 256) {
data_size = 0;
break;
}
float_to_timeval( &tv, op->CharTimeout);
FD_ZERO( &read_fd);
FD_SET( local_master->fd, &read_fd);
sts = select( local_master->fd + 1, &read_fd, NULL, NULL, &tv);
if ( sts == 0) {
break;
}
sts = read( local_master->fd, telegram + data_size, 1);
}
if ( data_size < 2) {
op->ErrorCount++;
continue;
}
if ( op->Debug) {
int i;
pwr_tTime current;
char timstr[40];
time_GetTime( &current);
time_AtoAscii( &current, time_eFormat_Time, timstr, sizeof(timstr));
printf( "Rcv: %s %2d ", timstr, data_size);
for ( i = 0; i < data_size; i++)
printf( "%02d ", telegram[i]);
printf( "\n");
}
generate_crc( telegram, data_size - 2, crc);
if ( crc[0] != telegram[data_size-2] || crc[1] != telegram[data_size-1]) {
op->ErrorCount++;
continue;
}
op->RX_packets++;
rb = (rec_buf *) telegram;
fc = rb->fc;
time_GetTime( &local_master->last_req_time);
exception_code = 0;
switch ( fc) {
case pwr_eModbus_FCEnum_ReadHoldingRegisters: {
io_sCard *cardp;
io_sServerModuleLocal *local_card;
pwr_sClass_Modbus_RTU_ServerModule *mp;
read_req *rmsg = (read_req *)rb;
rsp_read msg;
int found;
short addr = ntohs( rmsg->addr);
short quant = ntohs( rmsg->quant);
unsigned char unit_id = rmsg->unit_id;
if ( quant < 1 || quant >= 0x07d0) {
exception_code = 3;
break;
}
/* Check the address */
found = 0;
for ( cardp = rp->cardlist; cardp; cardp = cardp->next) {
mp = (pwr_sClass_Modbus_RTU_ServerModule *) cardp->op;
if ( mp->UnitId == unit_id) {
local_card = cardp->Local;
found = 1;
break;
}
}
if ( !found) {
exception_code = 2;
break;
}
addr -= mp->ReadAddress;
if ( addr < 0 ||
addr + quant * 2 > local_card->output_size) {
exception_code = 2;
break;
}
msg.fc = fc;
msg.bc = quant * 2;
msg.unit_id = rmsg->unit_id;
thread_MutexLock( &local_master->mutex);
memcpy( msg.buf, (char *)local_card->output_area + addr, quant * 2);
thread_MutexUnlock( &local_master->mutex);
ssts = rtu_send( local_master, op, &msg, sizeof(msg) - sizeof(msg.buf) + quant * 2 - 2);
if (ssts < 0) {
op->Status = MB__CONNLOST;
break;
}
op->Status = MB__NORMAL;
op->TX_packets++;
break;
}
case pwr_eModbus_FCEnum_ReadCoils:
case pwr_eModbus_FCEnum_ReadDiscreteInputs: {
io_sCard *cardp;
io_sServerModuleLocal *local_card;
pwr_sClass_Modbus_RTU_ServerModule *mp;
read_req *rmsg = (read_req *)rb;
rsp_read msg;
int found;
unsigned char mask;
unsigned int bytes;
int i;
int offs;
short addr = ntohs( rmsg->addr);
short quant = ntohs( rmsg->quant);
unsigned char unit_id = rmsg->unit_id;
if ( quant < 1 || quant >= 0x07d0) {
exception_code = 3;
break;
}
/* Check the address */
found = 0;
for ( cardp = rp->cardlist; cardp; cardp = cardp->next) {
mp = (pwr_sClass_Modbus_RTU_ServerModule *) cardp->op;
if ( mp->UnitId == unit_id) {
local_card = cardp->Local;
found = 1;
break;
}
}
if ( !found) {
exception_code = 2;
break;
}
offs = addr / 8;
bytes = (addr + quant) / 8 + (((addr + quant) % 8 == 0) ? 0 : 1) - offs;
if ( addr < 0 ||
offs + bytes + local_card->do_offset > local_card->output_size ||
offs + bytes > local_card->do_size) {
exception_code = 2;
break;
}
memset( &msg, 0, sizeof(msg));
msg.fc = fc;
msg.bc = bytes;
msg.unit_id = rmsg->unit_id;
thread_MutexLock( &local_master->mutex);
if ( addr % 8 == 0) {
memcpy( msg.buf, (char *)local_card->output_area + local_card->do_offset + addr/8, bytes);
mask = 0;
for ( i = 0; i < quant % 8; i++)
mask |= 1 << i;
if ( quant % 8 != 0) {
unsigned char *b = (unsigned char *) msg.buf;
b[bytes - 1] &= mask;
}
}
else {
mb_shift_read( (unsigned char *)local_card->output_area + local_card->do_offset + addr / 8,
(unsigned char *)msg.buf,
addr % 8, quant);
}
thread_MutexUnlock( &local_master->mutex);
ssts = rtu_send( local_master, op, &msg, sizeof(msg) - sizeof(msg.buf) + bytes - 2);
if (ssts < 0) {
op->Status = MB__CONNLOST;
break;
}
op->Status = MB__NORMAL;
op->TX_packets++;
break;
}
case pwr_eModbus_FCEnum_WriteSingleRegister: {
io_sCard *cardp;
io_sServerModuleLocal *local_card;
pwr_sClass_Modbus_RTU_ServerModule *mp;
write_single_req *rmsg = (write_single_req *)rb;
rsp_single_write msg;
int found;
short addr = ntohs( rmsg->addr);
unsigned char unit_id = rmsg->unit_id;
/* Check the address */
found = 0;
for ( cardp = rp->cardlist; cardp; cardp = cardp->next) {
mp = (pwr_sClass_Modbus_RTU_ServerModule *) cardp->op;
if ( mp->UnitId == unit_id) {
local_card = cardp->Local;
found = 1;
break;
}
}
if ( !found) {
exception_code = 2;
break;
}
addr -= mp->WriteAddress;
if ( addr < 0 ||
addr + 2 > local_card->input_size) {
exception_code = 2;
break;
}
thread_MutexLock( &local_master->mutex);
memcpy( (char *)local_card->input_area + addr, &rmsg->value, 2);
thread_MutexUnlock( &local_master->mutex);
msg.fc = fc;
msg.addr = rmsg->addr;
msg.value = rmsg->value;
msg.unit_id = rmsg->unit_id;
ssts = rtu_send( local_master, op, &msg, sizeof(msg) - 2);
if (ssts < 0) {
op->Status = MB__CONNLOST;
break;
}
op->Status = MB__NORMAL;
op->TX_packets++;
break;
}
case pwr_eModbus_FCEnum_WriteMultipleRegisters: {
io_sCard *cardp;
io_sServerModuleLocal *local_card;
pwr_sClass_Modbus_RTU_ServerModule *mp;
write_reg_req *rmsg = (write_reg_req *)rb;
rsp_write msg;
int found;
short addr = ntohs( rmsg->addr);
short quant = ntohs( rmsg->quant);
unsigned char unit_id = rmsg->unit_id;
if ( quant < 1 || quant >= 0x07d0) {
exception_code = 3;
break;
}
/* Check the address */
found = 0;
for ( cardp = rp->cardlist; cardp; cardp = cardp->next) {
mp = (pwr_sClass_Modbus_RTU_ServerModule *) cardp->op;
if ( mp->UnitId == unit_id) {
local_card = cardp->Local;
found = 1;
break;
}
}
if ( !found) {
exception_code = 2;
break;
}
addr -= mp->WriteAddress;
if ( addr < 0 ||
addr + quant * 2 > local_card->input_size) {
exception_code = 2;
break;
}
thread_MutexLock( &local_master->mutex);
memcpy( (char *)local_card->input_area + addr, rmsg->reg, quant * 2);
thread_MutexUnlock( &local_master->mutex);
msg.fc = fc;
msg.addr = rmsg->addr;
msg.quant = rmsg->quant;
msg.unit_id = rmsg->unit_id;
ssts = rtu_send( local_master, op, &msg, sizeof(msg) - 2);
if (ssts < 0) {
op->Status = MB__CONNLOST;
break;
}
op->Status = MB__NORMAL;
op->TX_packets++;
break;
}
case pwr_eModbus_FCEnum_WriteSingleCoil: {
io_sCard *cardp;
io_sServerModuleLocal *local_card;
pwr_sClass_Modbus_RTU_ServerModule *mp;
write_single_req *rmsg = (write_single_req *)rb;
rsp_single_write msg;
int found;
unsigned char mask;
int offs;
short addr = ntohs( rmsg->addr);
unsigned short value = ntohs( rmsg->value);
unsigned char unit_id = rmsg->unit_id;
/* Check the address */
found = 0;
for ( cardp = rp->cardlist; cardp; cardp = cardp->next) {
mp = (pwr_sClass_Modbus_RTU_ServerModule *) cardp->op;
if ( mp->UnitId == unit_id) {
local_card = cardp->Local;
found = 1;
break;
}
}
if ( !found) {
exception_code = 2;
break;
}
offs = addr / 8;
if ( addr < 0 ||
offs + local_card->di_offset >= local_card->input_size ||
offs >= local_card->di_size) {
exception_code = 2;
break;
}
mask = 1 << (addr % 8);
if ( value == 0xFF00 || value == 0) {
thread_MutexLock( &local_master->mutex);
if ( value == 0xFF00)
*((char *)local_card->input_area + local_card->di_offset + offs) |= mask;
else
*((char *)local_card->input_area + local_card->di_offset + offs) &= ~mask;
thread_MutexUnlock( &local_master->mutex);
}
msg.fc = fc;
msg.addr = rmsg->addr;
msg.value = rmsg->value;
msg.unit_id = rmsg->unit_id;
ssts = rtu_send( local_master, op, &msg, sizeof(msg) - 2);
if (ssts < 0) {
op->Status = MB__CONNLOST;
break;
}
op->Status = MB__NORMAL;
op->TX_packets++;
break;
}
case pwr_eModbus_FCEnum_WriteMultipleCoils: {
io_sCard *cardp;
io_sServerModuleLocal *local_card;
pwr_sClass_Modbus_RTU_ServerModule *mp;
write_reg_req *rmsg = (write_reg_req *)rb;
rsp_write msg;
int found;
unsigned char mask;
unsigned int bytes;
int i;
int offs;
short addr = ntohs( rmsg->addr);
short quant = ntohs( rmsg->quant);
unsigned char unit_id = rmsg->unit_id;
if ( quant < 1 || quant >= 0x07d0) {
exception_code = 3;
break;
}
/* Check the address */
found = 0;
for ( cardp = rp->cardlist; cardp; cardp = cardp->next) {
mp = (pwr_sClass_Modbus_RTU_ServerModule *) cardp->op;
if ( mp->UnitId == unit_id) {
local_card = cardp->Local;
found = 1;
break;
}
}
if ( !found) {
exception_code = 2;
break;
}
thread_MutexLock( &local_master->mutex);
offs = addr / 8;
bytes = (addr + quant) / 8 + (((addr + quant) % 8 == 0) ? 0 : 1) - offs;
if ( addr < 0 ||
offs + bytes + local_card->di_offset > local_card->input_size ||
offs + bytes > local_card->di_size) {
exception_code = 2;
break;
}
if ( addr % 8 == 0) {
if ( quant % 8 != 0) {
mask = 0;
for ( i = 0; i < quant % 8; i++)
mask |= 1 << i;
memcpy( (char *)local_card->input_area + local_card->di_offset + addr / 8,
rmsg->reg, bytes - 1);
*((char *)local_card->input_area + local_card->di_offset + addr / 8 + bytes - 1) &= ~mask;
*((char *)local_card->input_area + local_card->di_offset + addr / 8 + bytes - 1) |= *((char *)rmsg->reg + bytes - 1) & mask;
}
else
memcpy( (char *)local_card->input_area + local_card->di_offset + addr / 8,
rmsg->reg, bytes);
}
else {
mb_shift_write( (unsigned char *)rmsg->reg,
(unsigned char *)local_card->input_area + local_card->di_offset + addr / 8,
addr % 8, quant);
}
thread_MutexUnlock( &local_master->mutex);
msg.fc = fc;
msg.addr = rmsg->addr;
msg.quant = rmsg->quant;
msg.unit_id = rmsg->unit_id;
ssts = rtu_send( local_master, op, &msg, sizeof(msg) - 2);
if (ssts < 0) {
op->Status = MB__CONNLOST;
break;
}
op->Status = MB__NORMAL;
op->TX_packets++;
break;
}
case 43: {
/* Encapsulated Interface Transport, Read Device Identification */
read_dev_id_req *rmsg = (read_dev_id_req *)rb;
rsp_dev_id msg;
int i;
int len;
if ( rmsg->mei_type != 0x2b) {
exception_code = 1;
break;
}
if ( rmsg->id_code != 1) {
exception_code = 1;
break;
}
if ( rmsg->object_id != 0) {
exception_code = 1;
break;
}
msg.fc = rmsg->fc;
msg.mei_type = rmsg->mei_type;
msg.id_code = rmsg->id_code;
msg.conformity_level = 1;
msg.more_follows = 0;
msg.next_object_id = 0;
msg.number_of_objects = 3;
i = 0;
/* Vendor name */
msg.list[i++] = 0;
len = strlen("Proview");
msg.list[i++] = len;
strncpy( (char *)&msg.list[i], "Proview", len);
i += len;
/* Product code */
msg.list[i++] = 0;
len = strlen("-");
msg.list[i++] = len;
strncpy( (char *)&msg.list[i], "-", len);
i += len;
/* Major Minor Revision */
msg.list[i++] = 0;
len = strlen(pwrv_cPwrVersionStr);
msg.list[i++] = len;
strncpy( (char *)&msg.list[i], pwrv_cPwrVersionStr, len);
i += len;
msg.unit_id = rmsg->unit_id;
ssts = rtu_send( local_master, op, &msg, sizeof(msg) - sizeof(msg.list) + 1 - 2);
if (ssts < 0) {
op->Status = MB__CONNLOST;
break;
}
op->Status = MB__NORMAL;
op->TX_packets++;
break;
}
default:
exception_code = 1;
}
if ( exception_code) {
rsp_fault rsp_f;
rsp_f.fc = fc + 0x80;
rsp_f.ec = exception_code;
rsp_f.unit_id = rb->unit_id;
ssts = rtu_send( local_master, op, &rsp_f, sizeof(rsp_f) - 2);
if (ssts < 0) {
op->Status = MB__CONNLOST;
break;
}
op->Status = MB__NORMAL;
op->TX_packets++;
}
}
return 0;
}
/*----------------------------------------------------------------------------*\
Init method for the Modbus/RTU server
\*----------------------------------------------------------------------------*/
static pwr_tStatus IoRackInit (
io_tCtx ctx,
io_sAgent *ap,
io_sRack *rp
)
{
struct termios tty_attributes;
io_sServerLocal *local;
pwr_tStatus sts;
pwr_sClass_Modbus_RTU_Server *op;
pwr_tOName name;
mb_sCondata *condata;
op = (pwr_sClass_Modbus_RTU_Server *) rp->op;
sts = gdh_ObjidToName( rp->Objid, (char *) &name, sizeof(name), cdh_mNName);
errh_Info( "Init of Modbus RTU Server %s", name);
rp->Local = calloc(1, sizeof(io_sServerLocal));
local = rp->Local;
if ( op->DisableServer)
return IO__SUCCESS;
local->fd = open( op->Device, O_RDWR | O_NDELAY | O_NOCTTY);
if ( local->fd == -1) {
errh_Error( "Modbus RTU Master, open device error, %s", ap->Name);
return IO__ERRINIDEVICE;
}
tcgetattr( local->fd, &tty_attributes);
tty_attributes.c_cc[VMIN] = 1;
tty_attributes.c_cc[VTIME] = 0;
tty_attributes.c_lflag &= ~(ICANON | ISIG | ECHO | IEXTEN);
tty_attributes.c_cflag |= (CLOCAL | CREAD);
tty_attributes.c_oflag &= ~(OPOST);
tty_attributes.c_oflag &= ~(ONLCR);
tty_attributes.c_iflag &= ~(INLCR | ICRNL);
/* Speed */
#if defined OS_LINUX
tty_attributes.c_cflag &= ~CBAUD;
#endif
switch( op->Speed) {
case 300:
tty_attributes.c_cflag |= B300;
break;
case 1200:
tty_attributes.c_cflag |= B1200;
break;
case 2400:
tty_attributes.c_cflag |= B2400;
break;
case 4800:
tty_attributes.c_cflag |= B4800;
break;
case 9600:
tty_attributes.c_cflag |= B9600;
break;
case 19200:
tty_attributes.c_cflag |= B19200;
break;
default:
errh_Error( "Modbus RTU Master, unsupported speed, %s", ap->Name);
tty_attributes.c_cflag |= B9600;
break;
}
/* DataBits 5, 6, 7 or 8 */
tty_attributes.c_cflag &= ~CSIZE;
switch ( op->DataBits) {
case pwr_eDataBitsEnum_5:
tty_attributes.c_cflag |= CS5;
break;
case pwr_eDataBitsEnum_6:
tty_attributes.c_cflag |= CS6;
break;
case pwr_eDataBitsEnum_7:
tty_attributes.c_cflag |= CS7;
break;
case pwr_eDataBitsEnum_8:
tty_attributes.c_cflag |= CS8;
break;
default:
errh_Error( "Modbus RTU Master, unsupported DataBits, %s", ap->Name);
tty_attributes.c_cflag |= CS8;
}
//tty_attributes.c_iflag |=ISTRIP;
/* Parity */
switch ( op->Parity) {
case pwr_eParityEnum_Odd:
case pwr_eParityEnum_Even:
tty_attributes.c_cflag |= PARENB;
tty_attributes.c_iflag |= IGNPAR;
if ( op->Parity == pwr_eParityEnum_Even)
tty_attributes.c_cflag &= ~PARODD;
else
tty_attributes.c_cflag |= PARODD;
break;
default:
tty_attributes.c_cflag &= ~PARENB;
}
/* stopbitsval */
switch ( op->StopBits) {
case pwr_eStopBitsEnum_2:
tty_attributes.c_cflag |=CSTOPB;
break;
case pwr_eStopBitsEnum_1:
tty_attributes.c_cflag &=~CSTOPB;
break;
case pwr_eStopBitsEnum_0:
errh_Error( "Modbus RTU Master, unsupported StopBits, %s", ap->Name);
tty_attributes.c_cflag &=~CSTOPB;
break;
}
tty_attributes.c_iflag &= ~IXON; //ingen XON/XOFF in
//tty_attributes.c_iflag &= (V_IGNCR);
//tty_attributes.c_iflag &= (IGNPAR | V_IGNCR);
//tty_attributes.c_iflag &= ~(BRKINT | IXON | V_INLCR | V_ICRNL);
//tty_attributes.c_cflag &= ~(CSIZE | CSTOPB | PARENB); //fippla om vrden lite granna
sts = tcsetattr( local->fd, TCSANOW, &tty_attributes);
if ( sts < 0) {
errh_Error( "Modbus RTU Master, set device attributes error, %s", ap->Name);
return IO__ERRINIDEVICE;
}
sts = mb_init_channels( ctx, ap, rp);
if ( EVEN(sts)) return sts;
/* Create mutex */
sts = thread_MutexInit( &local->mutex);
if ( EVEN(sts)) {
errh_Error( "Error creating mutex IO modbus rtu server %s", rp->Name);
return IO__ERRINIDEVICE;
}
/* Create a thread for receive */
condata = (mb_sCondata *) malloc( sizeof(mb_sCondata));
condata->rp = rp;
sts = thread_Create( &local->receive_thread, 0, mb_receive, (void *)condata);
if ( EVEN(sts)) {
errh_Error( "Error creating receive thread IO modbus rtu server %s", rp->Name);
free( condata);
return IO__ERRINIDEVICE;
}
op->Status = MB__NORMAL;
return IO__SUCCESS;
}
static pwr_tStatus mb_init_channels( io_tCtx ctx, io_sAgent *ap, io_sRack *rp)
{
io_sServerModuleLocal *local_card;
io_sCard *cardp;
io_sServerLocal *local;
short input_counter;
short output_counter;
short card_input_counter;
short card_output_counter;
pwr_sClass_Modbus_RTU_Server *op;
pwr_sClass_Modbus_RTU_ServerModule *mp;
char name[196];
pwr_tStatus sts;
pwr_tCid cid;
io_sChannel *chanp;
int i, latent_input_counter, latent_output_counter;
pwr_tInt32 chan_size;
pwr_sClass_ChanDi *chan_di;
pwr_sClass_ChanDo *chan_do;
pwr_sClass_ChanAi *chan_ai;
pwr_sClass_ChanAit *chan_ait;
pwr_sClass_ChanIi *chan_ii;
pwr_sClass_ChanAo *chan_ao;
pwr_sClass_ChanIo *chan_io;
sts = gdh_ObjidToName(rp->Objid, (char *) &name, sizeof(name), cdh_mNName);
op = (pwr_sClass_Modbus_RTU_Server *) rp->op;
local = rp->Local;
/* Create socket, store in local struct */
/* Do configuration check and initialize modules. */
cardp = rp->cardlist;
input_counter = 0;
output_counter = 0;
card_input_counter = 0;
card_output_counter = 0;
latent_input_counter = 0;
latent_output_counter = 0;
while(cardp) {
local_card = calloc(1, sizeof(*local_card));
cardp->Local = local_card;
input_counter = input_counter + card_input_counter + latent_input_counter;
output_counter = output_counter + card_output_counter + latent_output_counter;
local_card->input_area = (void *) &(op->Inputs) + input_counter;
local_card->output_area = (void *) &(op->Outputs) + output_counter;
card_input_counter = 0;
card_output_counter = 0;
latent_input_counter = 0;
latent_output_counter = 0;
/* From v4.1.3 we can have subclasses, find the super class */
cid = cardp->Class;
while ( ODD( gdh_GetSuperClass( cid, &cid, cardp->Objid))) ;
switch (cid) {
case pwr_cClass_Modbus_RTU_ServerModule:
mp = (pwr_sClass_Modbus_RTU_ServerModule *) cardp->op;
mp->Status = pwr_eModbusModule_StatusEnum_StatusUnknown;
for (i = 0; i < cardp->ChanListSize; i++) {
chanp = &cardp->chanlist[i];
if ( is_diag( &chanp->ChanAref)) {
chanp->udata |= PB_UDATA_DIAG;
switch (chanp->ChanClass) {
case pwr_cClass_ChanIi:
chanp->offset = ((pwr_sClass_ChanIi *)chanp->cop)->Number;
chanp->size = GetChanSize( ((pwr_sClass_ChanIi *)chanp->cop)->Representation);
break;
default:
errh_Error( "Diagnostic channel class, card %s", cardp->Name);
}
continue;
}
if (chanp->ChanClass != pwr_cClass_ChanDi) {
card_input_counter += latent_input_counter;
latent_input_counter = 0;
}
if (chanp->ChanClass != pwr_cClass_ChanDo) {
card_output_counter += latent_output_counter;
latent_output_counter = 0;
}
switch (chanp->ChanClass) {
case pwr_cClass_ChanDi:
chan_di = (pwr_sClass_ChanDi *) chanp->cop;
if (chan_di->Number == 0) {
card_input_counter += latent_input_counter;
latent_input_counter = 0;
}
chanp->offset = card_input_counter;
chanp->mask = 1 << chan_di->Number;
if (chan_di->Representation == pwr_eDataRepEnum_Bit16)
chanp->mask = swap16(chanp->mask);
if (chan_di->Representation == pwr_eDataRepEnum_Bit32)
chanp->mask = swap32((unsigned short) chanp->mask);
if (chan_di->Number == 0) latent_input_counter = GetChanSize(chan_di->Representation);
if (local_card->di_size == 0)
local_card->di_offset = chanp->offset;
if (chan_di->Number == 0 || local_card->di_size == 0)
local_card->di_size += GetChanSize(chan_di->Representation);
// printf("Di channel found in %s, Number %d, Offset %d\n", cardp->Name, chan_di->Number, chanp->offset);
break;
case pwr_cClass_ChanAi:
chan_ai = (pwr_sClass_ChanAi *) chanp->cop;
chanp->offset = card_input_counter;
chan_size = GetChanSize(chan_ai->Representation);
chanp->size = chan_size;
chanp->mask = 0;
card_input_counter += chan_size;
io_AiRangeToCoef(chanp);
// printf("Ai channel found in %s, Number %d, Offset %d\n", cardp->Name, chan_ai->Number, chanp->offset);
break;
case pwr_cClass_ChanAit:
chan_ait = (pwr_sClass_ChanAit *) chanp->cop;
chanp->offset = card_input_counter;
chan_size = GetChanSize(chan_ait->Representation);
chanp->size = chan_size;
chanp->mask = 0;
card_input_counter += chan_size;
io_AiRangeToCoef(chanp);
break;
case pwr_cClass_ChanIi:
chan_ii = (pwr_sClass_ChanIi *) chanp->cop;
chanp->offset = card_input_counter;
chan_size = GetChanSize(chan_ii->Representation);
chanp->size = chan_size;
chanp->mask = 0;
card_input_counter += chan_size;
// printf("Ii channel found in %s, Number %d, Offset %d\n", cardp->Name, chan_ii->Number, chanp->offset);
break;
case pwr_cClass_ChanDo:
chan_do = (pwr_sClass_ChanDo *) chanp->cop;
if (chan_do->Number == 0) {
card_output_counter += latent_output_counter;
latent_output_counter = 0;
}
chanp->offset = card_output_counter;
chan_size = GetChanSize(chan_do->Representation);
chanp->mask = 1 << chan_do->Number;
if (chan_do->Representation == pwr_eDataRepEnum_Bit16)
chanp->mask = swap16(chanp->mask);
if (chan_do->Representation == pwr_eDataRepEnum_Bit32)
chanp->mask = swap32((unsigned short) chanp->mask);
if (chan_do->Number == 0) latent_output_counter = GetChanSize(chan_do->Representation);
if (local_card->do_size == 0)
local_card->do_offset = chanp->offset;
if (chan_do->Number == 0 || local_card->do_size == 0)
local_card->do_size += GetChanSize(chan_do->Representation);
// printf("Do channel found in %s, Number %d, Offset %d\n", cardp->Name, chan_do->Number, chanp->offset);
break;
case pwr_cClass_ChanAo:
chan_ao = (pwr_sClass_ChanAo *) chanp->cop;
chanp->offset = card_output_counter;
chan_size = GetChanSize(chan_ao->Representation);
chanp->size = chan_size;
chanp->mask = 0;
card_output_counter += chan_size;
io_AoRangeToCoef(chanp);
// printf("Ao channel found in %s, Number %d, Offset %d\n", cardp->Name, chan_ao->Number, chanp->offset);
break;
case pwr_cClass_ChanIo:
chan_io = (pwr_sClass_ChanIo *) chanp->cop;
chanp->offset = card_output_counter;
chan_size = GetChanSize(chan_io->Representation);
chanp->size = chan_size;
chanp->mask = 0;
card_output_counter += chan_size;
// printf("Io channel found in %s, Number %d, Offset %d\n", cardp->Name, chan_io->Number, chanp->offset);
break;
}
} /* End - for ... */
break;
} /* End - switch ... */
local_card->input_size = card_input_counter + latent_input_counter;
local_card->output_size = card_output_counter + latent_output_counter;
cardp = cardp->next;
}
local->input_size = input_counter + card_input_counter + latent_input_counter;
local->output_size = output_counter + card_output_counter + latent_output_counter;
return IO__SUCCESS;
}
static void mb_shift_write( unsigned char *in, unsigned char *out, int sh, int quant)
{
int i;
if ( sh + quant <= 8) {
unsigned char mask = 0;
for ( i = sh; i < sh + quant; i++)
mask |= 1 << i;
out[0] &= ~mask;
out[0] |= mask & (in[0] << sh);
return;
}
for ( i = 0; i < (quant + sh)/ 8; i++) {
if ( i == 0) {
unsigned char mask = ~0 << sh;
out[0] &= ~mask;
out[0] |= mask & (in[0] << sh);
}
else {
out[i] = in[i] << sh;
out[i] |= in[i-1] >> (8 - sh);
}
}
if ( (quant + sh) % 8 != 0) {
unsigned char mask = ~0 << ((quant + sh) % 8);
mask = ~mask;
out[i] &= ~mask;
out[i] |= mask & (in[i] << sh);
out[i] |= mask & (in[i-1] >> (8 - sh));
}
}
void mb_shift_read( unsigned char *in, unsigned char *out, int sh, int quant)
{
int i;
if ( sh + quant <= 8) {
unsigned char mask = ~0;
mask = mask >> (8 - quant);
out[0] = mask & (in[0] >> sh);
return;
}
for ( i = 0; i < quant / 8; i++) {
out[i] = in[i] >> sh;
out[i] |= in[i+1] << (8 - sh);
}
out[i] = in[i] >> sh;
if ( (quant + sh) / 8 > quant / 8)
out[i] |= in[i+1] << (8 - sh);
if ( quant % 8 != 0) {
unsigned char mask = ~0;
mask = mask >> (8 - (quant % 8));
out[i] &= mask;
}
}
/*----------------------------------------------------------------------------*\
Read method for the Modbus RTU server
\*----------------------------------------------------------------------------*/
static pwr_tStatus IoRackRead (
io_tCtx ctx,
io_sAgent *ap,
io_sRack *rp
)
{
return IO__SUCCESS;
}
/*----------------------------------------------------------------------------*\
Write method for the Modbus_RTU server
\*----------------------------------------------------------------------------*/
static pwr_tStatus IoRackWrite (
io_tCtx ctx,
io_sAgent *ap,
io_sRack *rp
)
{
return IO__SUCCESS;
}
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
static pwr_tStatus IoRackClose (
io_tCtx ctx,
io_sAgent *ap,
io_sRack *rp
)
{
io_sServerLocal* local = rp->Local;
close( local->fd);
return IO__SUCCESS;
}
/*----------------------------------------------------------------------------*\
Every method to be exported to the workbench should be registred here.
\*----------------------------------------------------------------------------*/
pwr_dExport pwr_BindIoMethods(Modbus_RTU_Server) = {
pwr_BindIoMethod(IoRackInit),
pwr_BindIoMethod(IoRackRead),
pwr_BindIoMethod(IoRackWrite),
pwr_BindIoMethod(IoRackClose),
pwr_NullMethod
};
/*
* Proview Open Source Process Control.
* Copyright (C) 2005-2011 SSAB Oxelosund AB.
*
* This file is part of Proview.
*
* 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 Proview. If not, see <http://www.gnu.org/licenses/>
*
* Linking Proview statically or dynamically with other modules is
* making a combined work based on Proview. Thus, the terms and
* conditions of the GNU General Public License cover the whole
* combination.
*
* In addition, as a special exception, the copyright holders of
* Proview give you permission to, from the build function in the
* Proview Configurator, combine Proview with modules generated by the
* Proview PLC Editor to a PLC program, regardless of the license
* terms of these modules. You may copy and distribute the resulting
* combined work under the terms of your choice, provided that every
* copy of the combined work is accompanied by a complete copy of
* the source code of Proview (the version used to produce the
* combined work), being distributed under the terms of the GNU
* General Public License plus this exception.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <math.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <unistd.h>
#include "pwr.h"
#include "pwr_baseclasses.h"
#include "pwr_basecomponentclasses.h"
#include "pwr_otherioclasses.h"
#include "rt_io_base.h"
#include "rt_io_msg.h"
#include "rt_errh.h"
#include "rt_io_bus.h"
#include "rt_mb_msg.h"
#include "rt_io_mb_rtu.h"
#include "co_time.h"
/*----------------------------------------------------------------------------*\
Init method for the Modbus server module
\*----------------------------------------------------------------------------*/
static pwr_tStatus IoCardInit (
io_tCtx ctx,
io_sAgent *ap,
io_sRack *rp,
io_sCard *cp
)
{
io_sServerModuleLocal *local;
pwr_sClass_Modbus_RTU_ServerModule *op;
int i;
op = (pwr_sClass_Modbus_RTU_ServerModule *) cp->op;
local = (io_sServerModuleLocal *) cp->Local;
for (i = 0; i < IO_MAXCHAN; i++) {
local->scancount[i] = 0;
}
op->Status = pwr_eModbusModule_StatusEnum_StatusUnknown;
return IO__SUCCESS;
}
/*----------------------------------------------------------------------------*\
Read method for the Modbus RTU server module
\*----------------------------------------------------------------------------*/
static pwr_tStatus IoCardRead (
io_tCtx ctx,
io_sAgent *ap,
io_sRack *rp,
io_sCard *cp
)
{
io_sServerModuleLocal *local;
io_sServerLocal *local_server;
pwr_sClass_Modbus_RTU_ServerModule *op;
pwr_sClass_Modbus_RTU_Server *server;
op = (pwr_sClass_Modbus_RTU_ServerModule *) cp->op;
local = (io_sServerModuleLocal *) cp->Local;
server = (pwr_sClass_Modbus_RTU_Server *) rp->op;
local_server = (io_sServerLocal *) rp->Local;
if ( server->DisableServer || !local)
return IO__SUCCESS;
if (server->Status == MB__NORMAL) {
thread_MutexLock( &local_server->mutex);
io_bus_card_read(ctx, rp, cp, local->input_area, NULL, pwr_eByteOrderingEnum_BigEndian, pwr_eFloatRepEnum_FloatIntel);
thread_MutexUnlock( &local_server->mutex);
}
// printf("Method Modbus_Module-IoCardRead\n");
return IO__SUCCESS;
}
/*----------------------------------------------------------------------------*\
Write method for the Modbus RTU server module
\*----------------------------------------------------------------------------*/
static pwr_tStatus IoCardWrite (
io_tCtx ctx,
io_sAgent *ap,
io_sRack *rp,
io_sCard *cp
)
{
io_sServerModuleLocal *local;
io_sServerLocal *local_server;
pwr_sClass_Modbus_RTU_ServerModule *op;
pwr_sClass_Modbus_RTU_Server *server;
op = (pwr_sClass_Modbus_RTU_ServerModule *) cp->op;
local = (io_sServerModuleLocal *) cp->Local;
server = (pwr_sClass_Modbus_RTU_Server *) rp->op;
local_server = (io_sServerLocal *) rp->Local;
if ( server->DisableServer || !local)
return IO__SUCCESS;
if (server->Status == MB__NORMAL) {
thread_MutexLock( &local_server->mutex);
io_bus_card_write(ctx, cp, local->output_area, pwr_eByteOrderingEnum_BigEndian, pwr_eFloatRepEnum_FloatIntel);
thread_MutexUnlock( &local_server->mutex);
}
// printf("Method Modbus_Module-IoCardWrite\n");
return IO__SUCCESS;
}
/*----------------------------------------------------------------------------*\
Every method to be exported to the workbench should be registred here.
\*----------------------------------------------------------------------------*/
pwr_dExport pwr_BindIoMethods(Modbus_RTU_ServerModule) = {
pwr_BindIoMethod(IoCardInit),
pwr_BindIoMethod(IoCardRead),
pwr_BindIoMethod(IoCardWrite),
pwr_NullMethod
};
/*
* Proview Open Source Process Control.
* Copyright (C) 2005-2011 SSAB Oxelosund AB.
*
* This file is part of Proview.
*
* 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 Proview. If not, see <http://www.gnu.org/licenses/>
*
* Linking Proview statically or dynamically with other modules is
* making a combined work based on Proview. Thus, the terms and
* conditions of the GNU General Public License cover the whole
* combination.
*
* In addition, as a special exception, the copyright holders of
* Proview give you permission to, from the build function in the
* Proview Configurator, combine Proview with modules generated by the
* Proview PLC Editor to a PLC program, regardless of the license
* terms of these modules. You may copy and distribute the resulting
* combined work under the terms of your choice, provided that every
* copy of the combined work is accompanied by a complete copy of
* the source code of Proview (the version used to produce the
* combined work), being distributed under the terms of the GNU
* General Public License plus this exception.
*/
/* rt_io_m_mb_rtu_slave.c -- io methods for a Modbus RTU slave */
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "pwr.h"
#include "co_cdh.h"
#include "pwr_baseclasses.h"
#include "pwr_basecomponentclasses.h"
#include "pwr_otherioclasses.h"
#include "rt_gdh.h"
#include "rt_io_base.h"
#include "rt_io_bus.h"
#include "rt_io_msg.h"
#include "rt_errh.h"
#include "co_cdh.h"
#include "co_time.h"
#include "rt_mb_msg.h"
#include "rt_io_mb_rtu.h"
/*----------------------------------------------------------------------------*\
Init method for the Modbus_TCP slave
\*----------------------------------------------------------------------------*/
static pwr_tStatus IoRackInit (
io_tCtx ctx,
io_sAgent *ap,
io_sRack *rp
)
{
io_sCardLocal *local_card;
io_sCard *cardp;
io_sRackLocal *local;
int no_di;
int no_do;
pwr_sClass_Modbus_RTU_Slave *op;
char name[196];
pwr_tStatus sts;
pwr_tCid cid;
io_sChannel *chanp;
int i;
sts = gdh_ObjidToName(rp->Objid, (char *) &name, sizeof(name), cdh_mNName);
errh_Info( "Init of Modbus TCP Slave and Modules %s", name);
op = (pwr_sClass_Modbus_RTU_Slave *) rp->op;
rp->Local = calloc(1, sizeof(io_sRackLocal));
local = rp->Local;
op->Status = MB__NORMAL;
/* Do configuration check and initialize modules. */
cardp = rp->cardlist;
unsigned int prev_input_area_offset = 0;
unsigned int prev_output_area_offset = 0;
unsigned int input_area_offset = 0;
unsigned int output_area_offset = 0;
unsigned int input_area_chansize = 0;
unsigned int output_area_chansize = 0;
while(cardp) {
local_card = calloc(1, sizeof(*local_card));
cid = cardp->Class;
/* Find the super class */
while ( ODD( gdh_GetSuperClass( cid, &cid, cardp->Objid))) ;
switch (cid) {
case pwr_cClass_Modbus_RTU_Module: {
pwr_sClass_Modbus_RTU_Module *modulep;
cardp->Local = local_card;
no_di = 0;
no_do = 0;
local_card->msg[0].input_area = (void *) &(op->Inputs) + input_area_offset +
input_area_chansize;
local_card->msg[0].output_area = (void *) &(op->Outputs) + output_area_offset +
output_area_chansize;
modulep = (pwr_sClass_Modbus_RTU_Module *) cardp->op;
modulep->Status = pwr_eModbusModule_StatusEnum_StatusUnknown;
io_bus_card_init( ctx, cardp, &input_area_offset, &input_area_chansize,
&output_area_offset, &output_area_chansize,
pwr_eByteOrderingEnum_BigEndian);
/* Count number of di and do */
for (i = 0; i < cardp->ChanListSize; i++) {
chanp = &cardp->chanlist[i];
switch (chanp->ChanClass) {
case pwr_cClass_ChanDi:
no_di++;
break;
case pwr_cClass_ChanDo:
no_do++;
break;
}
}
local_card->msg[0].input_size = input_area_offset + input_area_chansize -
prev_input_area_offset;
local_card->msg[0].output_size = output_area_offset + output_area_chansize -
prev_output_area_offset;
local_card->msg[0].no_di = no_di;
local_card->msg[0].no_do = no_do;
break;
}
} /* End - switch ... */
prev_input_area_offset = input_area_offset + input_area_chansize;
prev_output_area_offset = output_area_offset + output_area_chansize;
cardp = cardp->next;
}
local->input_size = input_area_offset + input_area_chansize;
local->output_size = output_area_offset + output_area_chansize;
return IO__SUCCESS;
}
/*----------------------------------------------------------------------------*\
Read method for the Modbus_TCP slave
\*----------------------------------------------------------------------------*/
static pwr_tStatus IoRackRead (
io_tCtx ctx,
io_sAgent *ap,
io_sRack *rp
)
{
#if 0
io_sRackLocal *local;
pwr_sClass_Modbus_TCP_Slave *sp;
pwr_tStatus sts;
pwr_tTime now;
pwr_tDeltaTime dt;
local = rp->Local;
sp = (pwr_sClass_Modbus_TCP_Slave *) rp->op;
/* Receive data */
if ((sp->Status == MB__NORMAL) && !sp->SingleOp) {
sts = mb_recv_data(local, rp, sp);
}
if (sp->DisableSlave != 1) {
if (sp->Status == MB__NORMAL) {
sp->ErrorCount = 0;
}
else {
sp->ErrorCount++;
}
if (sp->ErrorCount > sp->ErrorLimit) {
memset(&sp->Inputs, 0, local->input_size);
}
}
else {
sp->ErrorCount = 0;
sp->Status = MB__DISABLED;
}
#endif
return IO__SUCCESS;
}
/*----------------------------------------------------------------------------*\
Write method for the Modbus_TCP slave
\*----------------------------------------------------------------------------*/
static pwr_tStatus IoRackWrite (
io_tCtx ctx,
io_sAgent *ap,
io_sRack *rp
)
{
#if 0
io_sRackLocal *local;
pwr_sClass_Modbus_TCP_Slave *sp;
pwr_tStatus sts;
local = rp->Local;
sp = (pwr_sClass_Modbus_TCP_Slave *) rp->op;
local->expected_msgs = 0;
if (sp->Status == MB__NORMAL && sp->DisableSlave != 1) {
sts = mb_send_data( rp, ap->Local, local, ap->op, sp, mb_mSendMask_WriteReq);
}
if (sp->DisableSlave == 1) sp->Status = MB__DISABLED;
#endif
return IO__SUCCESS;
}
/*----------------------------------------------------------------------------*\
\*----------------------------------------------------------------------------*/
static pwr_tStatus IoRackClose (
io_tCtx ctx,
io_sAgent *ap,
io_sRack *rp
)
{
return IO__SUCCESS;
}
/*----------------------------------------------------------------------------*\
Every method to be exported to the workbench should be registred here.
\*----------------------------------------------------------------------------*/
pwr_dExport pwr_BindIoMethods(Modbus_RTU_Slave) = {
pwr_BindIoMethod(IoRackInit),
pwr_BindIoMethod(IoRackRead),
pwr_BindIoMethod(IoRackWrite),
pwr_BindIoMethod(IoRackClose),
pwr_NullMethod
};
/*
* Proview Open Source Process Control.
* Copyright (C) 2005-2011 SSAB Oxelosund AB.
*
* This file is part of Proview.
*
* 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 Proview. If not, see <http://www.gnu.org/licenses/>
*
* Linking Proview statically or dynamically with other modules is
* making a combined work based on Proview. Thus, the terms and
* conditions of the GNU General Public License cover the whole
* combination.
*
* In addition, as a special exception, the copyright holders of
* Proview give you permission to, from the build function in the
* Proview Configurator, combine Proview with modules generated by the
* Proview PLC Editor to a PLC program, regardless of the license
* terms of these modules. You may copy and distribute the resulting
* combined work under the terms of your choice, provided that every
* copy of the combined work is accompanied by a complete copy of
* the source code of Proview (the version used to produce the
* combined work), being distributed under the terms of the GNU
* General Public License plus this exception.
*/
#ifndef pwr_class_h
#include "pwr_class.h"
#endif
#define IO_MAXCHAN 96
#define MAX_MSGS_LOST 5
// These constants are obsolete from V4.1, except for the old style
// (Pb_Di, Pb_Do etc)
#define PB_MODULE_STATE_NOTINIT 0
#define PB_MODULE_STATE_OPERATE 1
#define PB_NUMREP_UNSIGNEDINT 0
#define PB_NUMREP_SIGNEDINT 1
#define PB_NUMREP_FLOATIEEE 2
#define PB_NUMREP_FLOATVAX 3
#define PB_NUMREP_FLOATINTEL 4
#define PB_ORIENTATION_BYTE 8
#define PB_ORIENTATION_WORD 16
#define PB_ORIENTATION_DWORD 32
#define PB_UDATA_DIAG 1
#define MB_MAX_CONNECTIONS 20
typedef pwr_tMask mb_tSendMask;
typedef enum {
mb_mSendMask_ReadReq = 1,
mb_mSendMask_WriteReq = 2,
} mb_mSendMask;
typedef struct {
int initialized;
int fd;
} io_sAgentLocal;
typedef struct {
int initialized;
short int trans_id;
int input_size;
int output_size;
int msgs_lost;
pwr_tTime last_try_connect_time;
int reset_inputs;
} io_sRackLocal;
typedef struct {
void *input_area;
void *output_area;
int scancount[IO_MAXCHAN];
int trans_id;
int input_size;
int output_size;
short int no_di;
short int no_do;
int interval_cnt;
int has_read_method;
} io_sCardLocalMsg;
typedef struct {
io_sCardLocalMsg msg[2];
} io_sCardLocal;
typedef struct {
int initialized;
int fd;
int input_size;
int output_size;
pwr_tTime last_req_time;
thread_sMutex mutex;
thread_s receive_thread;
} io_sServerLocal;
typedef struct {
void *input_area;
void *output_area;
int scancount[IO_MAXCHAN];
int trans_id;
int input_size;
int output_size;
int no_di;
int no_do;
int di_offset;
int do_offset;
int di_size;
int do_size;
} io_sServerModuleLocal;
#pragma pack(1)
typedef struct _read_req {
unsigned char unit_id;
unsigned char fc;
short int addr;
short int quant;
short int crc;
} read_req;
typedef struct _rec_buf {
unsigned char unit_id;
unsigned char fc;
unsigned char buf[255];
} rec_buf;
typedef struct _write_single_req {
unsigned char unit_id;
unsigned char fc;
short int addr;
short int value;
short int crc;
} write_single_req;
typedef struct _write_reg_req {
unsigned char unit_id;
unsigned char fc;
short int addr;
short int quant;
unsigned char bc;
short int reg[125];
short int crc;
} write_reg_req;
typedef struct _write_coils_req {
unsigned char unit_id;
unsigned char fc;
short int addr;
short int quant;
unsigned char bc;
unsigned char reg[247];
short int crc;
} write_coils_req;
typedef struct _read_dev_id_req {
unsigned char unit_id;
unsigned char fc;
unsigned char mei_type;
unsigned char id_code;
unsigned char object_id;
short int crc;
} read_dev_id_req;
typedef struct _res_write {
unsigned char unit_id;
unsigned char fc;
short int addr;
short int quant;
unsigned char buf[248];
short int crc;
} res_write;
typedef struct _res_read {
unsigned char unit_id;
unsigned char fc;
unsigned char bc;
unsigned char buf[251];
short int crc;
} res_read;
typedef struct _res_fault {
unsigned char unit_id;
unsigned char fc;
unsigned char ec;
short int crc;
} res_fault;
typedef struct _rsp_fault {
unsigned char unit_id;
unsigned char fc;
unsigned char ec;
short int crc;
} rsp_fault;
typedef struct _rsp_read {
unsigned char unit_id;
unsigned char fc;
unsigned char bc;
unsigned char buf[250];
short int crc;
} rsp_read;
typedef struct _rsp_write {
unsigned char unit_id;
unsigned char fc;
short int addr;
short int quant;
short int crc;
} rsp_write;
typedef struct _rsp_single_write {
unsigned char unit_id;
unsigned char fc;
short int addr;
short int value;
short int crc;
} rsp_single_write;
typedef struct _rsp_dev_id {
unsigned char unit_id;
unsigned char fc;
unsigned char mei_type;
unsigned char id_code;
unsigned char conformity_level;
unsigned char more_follows;
unsigned char next_object_id;
unsigned char number_of_objects;
unsigned char list[80];
short int crc;
} rsp_dev_id;
#pragma pack(0)
pwr_tStatus mb_recv_data(io_sRackLocal *local,
io_sRack *rp,
pwr_sClass_Modbus_TCP_Slave *sp);
pwr_tStatus mb_send_data(io_sRackLocal *local,
io_sRack *rp,
pwr_sClass_Modbus_TCP_Slave *sp,
mb_tSendMask mask);
......@@ -6,6 +6,11 @@ Modbus_ModuleReadWrite
Modbus_Master
Modbus_TCP_Server
Modbus_TCP_ServerModule
Modbus_RTU_Slave
Modbus_RTU_Module
Modbus_RTU_Master
Modbus_RTU_Server
Modbus_RTU_ServerModule
Arduino_Uno
#if OS_LINUX
GPIO
......
Volume OtherIO $ClassVolume 0.0.250.10
Body SysBody 01-JAN-1970 01:00:00.00
Attr NextOix = "_X267"
Attr NextCix = "_X29"
Attr NextOix = "_X295"
Attr NextCix = "_X34"
Attr NextTix[0] = "_X10"
EndBody
Object Type $TypeHier 1 15-NOV-2007 14:35:37.90
......@@ -814,7 +814,7 @@ Volume OtherIO $ClassVolume 0.0.250.10
Object RtBody $ObjBodyDef 1 08-FEB-2008 10:26:36.84
Body SysBody 08-FEB-2008 10:26:36.85
Attr StructName = "Modbus_TCP_Slave"
Attr NextAix = "_X20"
Attr NextAix = "_X21"
EndBody
!/**
! Description of slave
......@@ -882,6 +882,10 @@ Volume OtherIO $ClassVolume 0.0.250.10
Attr TypeRef = "pwrs:Type-$String32"
EndBody
EndObject
!/**
! The default port for Modbus TCP is 502. If another port should be
! used it is specifiec here.
!*/
Object Port $Attribute 19 04-DEC-2009 17:22:45.73
Body SysBody 04-DEC-2009 17:23:01.72
Attr PgmName = "Port"
......@@ -899,6 +903,19 @@ Volume OtherIO $ClassVolume 0.0.250.10
EndBody
EndObject
!/**
! Specifies the action when the errorcounter has reached the error limit.
!
! No no action.
! Reset inputs the inputs for the slave are reset.
! Emergency break all I/O is stopped.
!*/
Object StallAction $Attribute 20 27-OCT-2011 08:54:41.57
Body SysBody 27-OCT-2011 08:54:45.34
Attr PgmName = "StallAction"
Attr TypeRef = "pwrb:Type-StallActionEnum"
EndBody
EndObject
!/**
! @Summary Error count of the slave.
! ErrorCount will increase every cycle if status is not MB__NORMAL.
! When ErrorCount reaches the ErrorLimit all inputs are reset to zero.
......@@ -994,7 +1011,7 @@ Volume OtherIO $ClassVolume 0.0.250.10
EndObject
!/**
! @Summary Input area.
! Area where alla input data is stored.
! Area where all input data is stored.
!*/
Object Inputs $Attribute 14 08-FEB-2008 10:59:26.76
Body SysBody 08-FEB-2008 11:00:29.99
......@@ -1006,7 +1023,7 @@ Volume OtherIO $ClassVolume 0.0.250.10
EndObject
!/**
! @Summary Output area.
! Area where alla output data is stored.
! Area where all output data is stored.
!*/
Object Outputs $Attribute 15 08-FEB-2008 11:00:48.44
Body SysBody 08-FEB-2008 11:00:44.86
......@@ -1175,6 +1192,9 @@ Volume OtherIO $ClassVolume 0.0.250.10
Attr TypeRef = "pwrs:Type-$UInt16"
EndBody
EndObject
!/**
! Module status.
!*/
Object Status $Attribute 7 08-FEB-2008 11:20:34.93
Body SysBody 04-DEC-2009 17:15:47.85
Attr PgmName = "Status"
......@@ -1401,11 +1421,12 @@ Volume OtherIO $ClassVolume 0.0.250.10
! @b See also
! @classlink Modbus_ModuleMsg otherio_modbus_modulemsg.html
! @classlink Modbus_Module otherio_modbus_module.html
!*/
Object Modbus_ModuleReadWrite $ClassDef 27 17-OCT-2011 07:54:13.97
Body SysBody 17-OCT-2011 07:54:45.40
Attr Editor = 0
Attr Method = 0
Attr Flags = 18512
Attr Flags = 51280
EndBody
Object RtBody $ObjBodyDef 1 17-OCT-2011 07:56:53.34
Body SysBody 17-OCT-2011 07:56:53.34
......@@ -1753,7 +1774,7 @@ Volume OtherIO $ClassVolume 0.0.250.10
EndObject
!/**
! @Summary Input area.
! Area where alla input data is stored.
! Area where all input data is stored.
!*/
Object Inputs $Attribute 36 27-NOV-2009 09:42:27.83
Body SysBody 27-NOV-2009 09:42:46.12
......@@ -1765,7 +1786,7 @@ Volume OtherIO $ClassVolume 0.0.250.10
EndObject
!/**
! @Summary Ouput area.
! Area where alla output data is stored.
! Area where all output data is stored.
!*/
Object Outputs $Attribute 37 27-NOV-2009 09:42:27.83
Body SysBody 27-NOV-2009 09:43:03.16
......@@ -1813,7 +1834,7 @@ Volume OtherIO $ClassVolume 0.0.250.10
!/**
! @Version 1.0
! @Group IO
! @Summary Server Modue object for Modbus TCP I/O.
! @Summary Server Module object for Modbus TCP I/O.
! Server Module object for Modbus TCP I/O.
!
! The Module object is placed as a child to a Modbus_TCP_Server object
......@@ -1875,7 +1896,7 @@ Volume OtherIO $ClassVolume 0.0.250.10
EndObject
!/**
! @Summary Unit id.
! Identification of the modbus unit to communicate with. It is typically
! Identification of the modbus server unit. It is typically
! only used if communicating with a tpc gateway that is connected to a
! Modbus serial line with possibly several units. Usually this has no
! meaning and should be set to zero (0).
......@@ -1951,6 +1972,1022 @@ Volume OtherIO $ClassVolume 0.0.250.10
EndBody
EndObject
EndObject
!/**
! @Version 1.0
! @Group IO
! @Summary Master object for Modbus RTU I/O.
! Master object for Modbus RTU I/O.
!
! @classlink Modbus_RTU_Module otherio_modbus_rtu_module.html
! @classlink Modbus_RTU_Slave otherio_modbus_rtu_slave.html
!*/
Object Modbus_RTU_Master $ClassDef 29 18-OCT-2011 11:07:34.64
Body SysBody 18-OCT-2011 11:07:05.53
Attr Editor = 0
Attr Method = 0
Attr Flags = 38992
EndBody
Object RtBody $ObjBodyDef 1 18-OCT-2011 11:07:05.53
Body SysBody 18-OCT-2011 11:07:44.18
Attr StructName = "Modbus_RTU_Master"
Attr NextAix = "_X18"
EndBody
!/**
! Description of master.
!*/
Object Description $Attribute 5 18-OCT-2011 11:07:05.53
Body SysBody 18-OCT-2011 11:07:05.53
Attr PgmName = "Description"
Attr TypeRef = "pwrs:Type-$String80"
EndBody
EndObject
!/**
! If TRUE the master is disabled.
!*/
Object Disable $Attribute 6 18-OCT-2011 11:07:05.53
Body SysBody 18-OCT-2011 11:07:05.53
Attr PgmName = "Disable"
Attr TypeRef = "pwrs:Type-$Boolean"
EndBody
EndObject
!/**
! @Summary Process that handles the card. Plc(1), rt_io_comm(2) or application process(4).
! Process that handles the master.
!
! 1: The master is read by the plc process, and is handled by a specific
! thread in the plc, which is specified in the ThreadObject attribute.
! 2: The master is read by the rt_io_comm process.
! 4: The master is handled by an application program.
!*/
Object Process $Attribute 7 18-OCT-2011 11:07:05.53
Body SysBody 18-OCT-2011 11:07:05.53
Attr PgmName = "Process"
Attr TypeRef = "pwrb:Type-IoProcessMask"
EndBody
EndObject
!/**
! @Summary Plc thread that handles the master.
! The PlcThread object of the plc thread that handles the master.
! The master is read with the scantime of the thread.
!*/
Object ThreadObject $Attribute 8 18-OCT-2011 11:07:05.53
Body SysBody 18-OCT-2011 11:07:05.53
Attr PgmName = "ThreadObject"
Attr TypeRef = "pwrs:Type-$Objid"
EndBody
EndObject
!/**
! Device name of the serial port, e.g. /dev/ttyS0.
!*/
Object Device $Attribute 9 18-OCT-2011 11:08:23.34
Body SysBody 18-OCT-2011 11:08:38.79
Attr PgmName = "Device"
Attr TypeRef = "pwrs:Type-$String40"
EndBody
EndObject
!/**
! Baud rate of the serial port.
!*/
Object Speed $Attribute 10 18-OCT-2011 11:09:05.07
Body SysBody 18-OCT-2011 11:09:12.39
Attr PgmName = "Speed"
Attr TypeRef = "pwrs:Type-$UInt32"
EndBody
EndObject
!/**
! Parity of the serial port.
!*/
Object Parity $Attribute 11 18-OCT-2011 11:09:38.47
Body SysBody 18-OCT-2011 11:10:12.61
Attr PgmName = "Parity"
Attr TypeRef = "pwrb:Type-ParityEnum"
EndBody
EndObject
!/**
! Stop bits of the serial port.
!*/
Object StopBits $Attribute 12 18-OCT-2011 11:10:26.72
Body SysBody 18-OCT-2011 11:10:34.59
Attr PgmName = "StopBits"
Attr TypeRef = "pwrb:Type-StopBitsEnum"
EndBody
EndObject
!/**
! Data bits of the serial port.
!*/
Object DataBits $Attribute 13 18-OCT-2011 11:10:46.95
Body SysBody 18-OCT-2011 11:10:53.17
Attr PgmName = "DataBits"
Attr TypeRef = "pwrb:Type-DataBitsEnum"
EndBody
EndObject
!/**
! Timeout for character read.
!*/
Object CharTimeout $Attribute 14 25-OCT-2011 13:26:58.49
Body SysBody 25-OCT-2011 13:27:00.56
Attr PgmName = "CharTimeout"
Attr TypeRef = "pwrs:Type-$Float32"
EndBody
EndObject
!/**
! Time between frames.
!*/
Object FrameTimeout $Attribute 15 25-OCT-2011 13:27:08.81
Body SysBody 25-OCT-2011 13:27:09.97
Attr PgmName = "FrameTimeout"
Attr TypeRef = "pwrs:Type-$Float32"
EndBody
EndObject
!/**
! Timeout slave response.
!*/
Object ReceiveTimeout $Attribute 16 26-OCT-2011 16:57:52.50
Body SysBody 26-OCT-2011 16:57:53.52
Attr PgmName = "ReceiveTimeout"
Attr TypeRef = "pwrs:Type-$Float32"
EndBody
EndObject
!/**
! Print debug information.
!*/
Object Debug $Attribute 17 27-OCT-2011 08:55:53.85
Body SysBody 27-OCT-2011 08:58:09.11
Attr Flags = 25167872
Attr TypeRef = "pwrs:Type-$Boolean"
EndBody
EndObject
EndObject
Object IoMethods $RtMethod 268 18-OCT-2011 11:07:05.53
Object IoAgentInit $Method 269 18-OCT-2011 11:07:05.53
Body SysBody 18-OCT-2011 11:13:04.50
Attr MethodName = "Modbus_RTU_Master-IoAgentInit"
EndBody
EndObject
Object IoAgentRead $Method 270 18-OCT-2011 11:07:05.53
Body SysBody 18-OCT-2011 11:13:17.28
Attr MethodName = "Modbus_RTU_Master-IoAgentRead"
EndBody
EndObject
Object IoAgentWrite $Method 271 18-OCT-2011 11:07:05.53
Body SysBody 18-OCT-2011 11:13:27.20
Attr MethodName = "Modbus_RTU_Master-IoAgentWrite"
EndBody
EndObject
Object IoAgentClose $Method 272 18-OCT-2011 11:07:05.53
Body SysBody 18-OCT-2011 11:13:39.73
Attr MethodName = "Modbus_RTU_Master-IoAgentClose"
EndBody
EndObject
EndObject
Object PostCreate $DbCallBack 273 18-OCT-2011 11:07:05.53
Body SysBody 18-OCT-2011 11:07:05.53
Attr MethodName = "BaseIORack-PostCreate"
EndBody
EndObject
Object Template Modbus_RTU_Master 2155315200 01-JAN-1970 01:00:00.00
Body RtBody 26-OCT-2011 18:01:49.06
Attr Process = 1
Attr Device = "/dev/ttyS0"
Attr Speed = 9600
Attr StopBits = 2
Attr DataBits = 8
Attr CharTimeout = 2.000000e-02
Attr FrameTimeout = 1.000000e-02
Attr ReceiveTimeout = 5.000000e-01
EndBody
EndObject
EndObject
!/**
! @Version 1.0
! @Group IO
! @Summary Slave object for Modbus RTU I/O.
! Slave object for Modbus RTU I/O.
!
! @classlink Modbus_RTU_Master otherio_modbus_rtu_master.html
! @classlink Modbus_RTU_Module otherio_modbus_rtu_module.html
!*/
Object Modbus_RTU_Slave $ClassDef 30 18-OCT-2011 11:14:28.26
Body SysBody 18-OCT-2011 11:14:17.41
Attr Editor = 0
Attr Method = 0
Attr Flags = 43088
EndBody
Object RtBody $ObjBodyDef 1 25-OCT-2011 13:28:38.46
Body SysBody 18-OCT-2011 11:14:34.02
Attr StructName = "Modbus_RTU_Slave"
Attr NextAix = "_X39"
EndBody
!/**
! Description of slave
!*/
Object Description $Attribute 20 18-OCT-2011 11:14:17.41
Body SysBody 18-OCT-2011 11:14:17.41
Attr PgmName = "Description"
Attr TypeRef = "pwrs:Type-$String80"
EndBody
EndObject
!/**
! @Summary Datasheet.
! Link to datasheet for the specific slave type.
!*/
Object DataSheet $Attribute 21 18-OCT-2011 11:14:17.41
Body SysBody 18-OCT-2011 11:14:17.41
Attr PgmName = "DataSheet"
Attr TypeRef = "pwrs:Type-$URL"
EndBody
EndObject
!/**
! @Summary Status of the slave.
! Status of the slave. Shows if tcp-link to slave is up or not.
!*/
Object Status $Attribute 22 18-OCT-2011 11:14:17.41
Body SysBody 18-OCT-2011 11:14:17.41
Attr PgmName = "Status"
Attr Flags = 1040
Attr TypeRef = "pwrs:Type-$Status"
EndBody
EndObject
!/**
! @Summary Process that handles the slave. Plc(1), rt_io_comm(2) or application process(4).
! Process that handles the card.
!
! 1: The slave is read by the plc process, and is handled by a specific
! thread in the plc, which is specified in the ThreadObject attribute.
! 2: The slave is read by the rt_io_comm process.
! 4: The slave is handled by an application program.
!*/
Object Process $Attribute 23 18-OCT-2011 11:14:17.41
Body SysBody 18-OCT-2011 11:14:17.41
Attr PgmName = "Process"
Attr TypeRef = "pwrb:Type-IoProcessMask"
EndBody
EndObject
!/**
! @Summary Plc thread that handles the slave.
! The PlcThread object of the plc thread that handles the slave.
! The slave is read with the scantime of the thread.
!*/
Object ThreadObject $Attribute 24 18-OCT-2011 11:14:17.41
Body SysBody 18-OCT-2011 11:14:17.41
Attr PgmName = "ThreadObject"
Attr TypeRef = "pwrs:Type-$Objid"
EndBody
EndObject
!/**
! Specifies the action when the errorcounter has reached the error limit.
!
! No no action.
! Reset inputs the inputs for the slave are reset.
! Emergency break all I/O is stopped.
!*/
Object StallAction $Attribute 38 27-OCT-2011 08:52:20.96
Body SysBody 27-OCT-2011 08:53:31.33
Attr PgmName = "StallAction"
Attr TypeRef = "pwrb:Type-StallActionEnum"
EndBody
EndObject
!/**
! @Summary Flag that disables the slave.
! Flag that disables the initialization of the slave, if initialized turns off i/o-handling.
!*/
Object DisableSlave $Attribute 27 18-OCT-2011 11:14:17.41
Body SysBody 18-OCT-2011 11:14:17.41
Attr PgmName = "DisableSlave"
Attr TypeRef = "pwrb:Type-YesNoEnum"
EndBody
EndObject
!/**
! @Summary Error count of the slave.
! ErrorCount will increase every cycle if status is not MB__NORMAL.
! When ErrorCount reaches the ErrorLimit the action in StallAction is executed.
!*/
Object ErrorCount $Attribute 28 18-OCT-2011 11:14:17.41
Body SysBody 18-OCT-2011 11:14:17.41
Attr PgmName = "ErrorCount"
Attr Flags = 1040
Attr TypeRef = "pwrs:Type-$UInt16"
EndBody
EndObject
!/**
! @Summary Error limit of the slave.
! ErrorCount will increase every cycle if status is not MB__NORMAL.
! When ErrorCount reaches the ErrorLimit the action in StallAction is exectued.
!*/
Object ErrorLimit $Attribute 29 18-OCT-2011 11:14:17.41
Body SysBody 18-OCT-2011 11:14:17.41
Attr PgmName = "ErrorLimit"
Attr TypeRef = "pwrs:Type-$UInt16"
EndBody
EndObject
!/**
! @Summary Received number of messages from slave.
! Received number of messages from slave.
!*/
Object RX_packets $Attribute 34 18-OCT-2011 11:14:17.41
Body SysBody 18-OCT-2011 11:14:17.41
Attr PgmName = "RX_packets"
Attr Flags = 1040
Attr TypeRef = "pwrs:Type-$UInt32"
EndBody
EndObject
!/**
! @Summary Sent number of messages to slave.
! Sent number of messages to slave.
!*/
Object TX_packets $Attribute 35 18-OCT-2011 11:14:17.41
Body SysBody 18-OCT-2011 11:14:17.41
Attr PgmName = "TX_packets"
Attr Flags = 1040
Attr TypeRef = "pwrs:Type-$UInt32"
EndBody
EndObject
!/**
! @Summary Input area.
! Area where all input data is stored.
!*/
Object Inputs $Attribute 36 18-OCT-2011 11:14:17.41
Body SysBody 18-OCT-2011 11:14:17.41
Attr PgmName = "Inputs"
Attr Flags = 3074
Attr Elements = 256
Attr TypeRef = "pwrs:Type-$UInt8"
EndBody
EndObject
!/**
! @Summary Output area.
! Area where all output data is stored.
!*/
Object Outputs $Attribute 37 18-OCT-2011 11:14:17.41
Body SysBody 18-OCT-2011 11:14:17.41
Attr PgmName = "Outputs"
Attr Flags = 3074
Attr Elements = 256
Attr TypeRef = "pwrs:Type-$UInt8"
EndBody
EndObject
EndObject
Object IoMethods $RtMethod 274 18-OCT-2011 11:14:17.41
Object IoRackInit $Method 275 18-OCT-2011 11:14:17.41
Body SysBody 18-OCT-2011 11:16:56.30
Attr MethodName = "Modbus_RTU_Slave-IoRackInit"
EndBody
EndObject
Object IoRackClose $Method 276 18-OCT-2011 11:14:17.41
Body SysBody 18-OCT-2011 11:17:02.69
Attr MethodName = "Modbus_RTU_Slave-IoRackClose"
EndBody
EndObject
Object IoRackRead $Method 277 18-OCT-2011 11:14:17.41
Body SysBody 18-OCT-2011 11:17:08.79
Attr MethodName = "Modbus_RTU_Slave-IoRackRead"
EndBody
EndObject
Object IoRackWrite $Method 278 18-OCT-2011 11:14:17.41
Body SysBody 18-OCT-2011 11:17:15.19
Attr MethodName = "Modbus_RTU_Slave-IoRackWrite"
EndBody
EndObject
EndObject
Object PostCreate $DbCallBack 279 18-OCT-2011 11:14:17.41
Body SysBody 18-OCT-2011 11:14:17.41
Attr MethodName = "BaseIORack-PostCreate"
EndBody
EndObject
Object Template Modbus_RTU_Slave 2155577344 01-JAN-1970 01:00:00.00
Body RtBody 25-OCT-2011 13:31:22.94
Attr Process = 1
Attr ErrorLimit = 100
EndBody
EndObject
EndObject
!/**
! @Version 1.0
! @Group IO
! @Summary Module object for Modbus RTU I/O.
! Module object for Modbus RTU I/O.
! Defines the type of Modbus action that is to be performed and at which address on the slave.
! The action is defined by a function code which means either reading or writing data to
! the Modbus slave.
!
! The supported function codes are:
!
! @b ReadCoils (FC 1)
! This function code is used to read from 1 to 2000 contiguous status of coils in a remote device.
! Typically the input data area is defined by a number of ChanDi's which represent
! the number of coils you want to read. The represenation on the ChanDi should be set to Bit8.
!
! @b ReadDiscreteInputs (FC 2)
! This function code is used to read from 1 to 2000 contiguous status of discrete inputs
! in a remote device. Typically the input data area is defined by a number of ChanDi's
! which represent the number of coils you want to read.
! The represenation on the ChanDi should be set to Bit8.
!
! @b ReadHoldingRegisters (FC 3)
! This function code is used to read the contents of a contiguous block of holding registers
! in a remote device.
! Typically the input data area is defined by a number of ChanIi's which represent
! the number of registers you want to read. The represenation on the ChanIi should
! be set to UInt16 or Int16. ChanAi and ChanDi is also applicable. In case of ChanDi the
! representation should be set to Bit16.
!
! @b ReadInputRegisters (FC 4)
! This function code is used to read from 1 to 125 contiguous input registers
! in a remote device.
! Typically the input data area is defined by a number of ChanIi's which represent
! the number of registers you want to read. The represenation on the ChanIi should
! be set to UInt16 or Int16. ChanAi and ChanDi is also applicable. In case of ChanDi the
! representation should be set to Bit16.
!
! @b WriteSingleCoil (FC 5)
! This function code is used to write to one single coil.
! Typically the output data area is defined by one ChanDo's which represent
! the state of the coil to write to.
!
! @b WriteMultipleCoils (FC 15)
! This function code is used to force each coil in a sequence of coils to either ON or OFF
! in a remote Device.
! Typically the output data area is defined by a number of ChanDo's which represent
! the number of coils you want to write. The represenation on the ChanDo should
! be set to Bit8.
!
! @b WriteMultipleRegisters (FC 16)
! This function code is used to write a block of contiguous registers (1 to 123 registers)
! in a remote device.
! Typically the output data area is defined by a number of ChanIo's which represent
! the number of registers you want to write. The represenation on the ChanIo should
! be set to UInt16 or Int16. ChanAo and ChanDo is also applicable. In case of ChanDo the
! representation should be set to Bit16.
!
! @classlink Modbus_RTU_Master otherio_modbus_rtu_master.html
! @classlink Modbus_RTU_Slave otherio_modbus_rtu_slave.html
!*/
Object Modbus_RTU_Module $ClassDef 31 18-OCT-2011 11:18:19.61
Body SysBody 18-OCT-2011 11:18:07.74
Attr Editor = 0
Attr Method = 0
Attr Flags = 51280
EndBody
Object RtBody $ObjBodyDef 1 18-OCT-2011 11:18:07.74
Body SysBody 18-OCT-2011 11:18:24.86
Attr StructName = "Modbus_RTU_Module"
Attr NextAix = "_X22"
EndBody
!/**
! Description of module
!*/
Object Description $Attribute 12 18-OCT-2011 11:18:07.74
Body SysBody 18-OCT-2011 11:18:07.74
Attr PgmName = "Description"
Attr TypeRef = "pwrs:Type-$String80"
EndBody
EndObject
!/**
! @Summary Modbus function code.
! The function code defines the action that is to be perfomed with the Modbus slave.
! The module is handled with the scantime of the thread.
! The supported function codes are:
!
! (FC 1) ReadCoils
! (FC 2) ReadDiscreteInputs
! (FC 3) ReadHoldingRegisters
! (FC 4) ReadInputRegisters
! (FC 5) WriteSingleCoil
! (FC 15) WriteMultipleCoils
! (FC 16) WriteMultipleRegisters
!*/
Object FunctionCode $Attribute 13 18-OCT-2011 11:18:07.74
Body SysBody 18-OCT-2011 11:18:07.74
Attr PgmName = "FunctionCode"
Attr TypeRef = "OtherIO:Type-Modbus_FCEnum"
EndBody
EndObject
!/**
! @Summary Address of data area on Modbus slave.
! Address of data area on Modbus slave.
!*/
Object Address $Attribute 14 18-OCT-2011 11:18:07.74
Body SysBody 18-OCT-2011 11:18:07.74
Attr PgmName = "Address"
Attr TypeRef = "pwrs:Type-$UInt16"
EndBody
EndObject
!/**
! @Summary Unit id.
! Identification of the modbus unit to communicate with.
!*/
Object UnitId $Attribute 15 18-OCT-2011 11:18:07.74
Body SysBody 18-OCT-2011 11:18:07.74
Attr PgmName = "UnitId"
Attr TypeRef = "pwrs:Type-$UInt16"
EndBody
EndObject
!/**
! Module status.
!*/
Object Status $Attribute 16 18-OCT-2011 11:18:07.74
Body SysBody 18-OCT-2011 11:18:07.74
Attr PgmName = "Status"
Attr Flags = 1040
Attr TypeRef = "OtherIO:Type-ModbusModule_StatusEnum"
EndBody
EndObject
!/**
! @Summary Continous operation of the module.
! If set to Yes the module is scanned cylically for each scan (read or write operation).
! If set to false the action defined by the FunctionCode-attribute will only be executed
! when the SendOp-attribute is set.
!*/
Object Continous $Attribute 17 18-OCT-2011 11:18:07.74
Body SysBody 18-OCT-2011 11:18:07.74
Attr PgmName = "Continous"
Attr TypeRef = "pwrb:Type-YesNoEnum"
EndBody
EndObject
!/**
! @Summary Request to execute action defined by FunctionCode-attribute once.
! This attribute is only valid if Contious-attribute is set to 'No'.
!*/
Object SendOp $Attribute 18 18-OCT-2011 11:18:07.74
Body SysBody 18-OCT-2011 11:18:07.74
Attr PgmName = "SendOp"
Attr TypeRef = "pwrs:Type-$Boolean"
EndBody
EndObject
!/**
! Specifies, in relation to the scantime of the thread, how
! often the module is handled. If ScanInterval i 1, the module
! is handled every scan. If ScanInterval is for example 10, it
! is handled every 10'th scan, i.e. the scantime for the module
! will be ScanInterval times the scantime of the thread.
!*/
Object ScanInterval $Attribute 19 18-OCT-2011 11:18:07.74
Body SysBody 18-OCT-2011 11:18:07.74
Attr PgmName = "ScanInterval"
Attr TypeRef = "pwrs:Type-$UInt32"
EndBody
EndObject
!/**
! @Summary Process that handles the card. Plc(1), rt_io_comm(2) or application process(4).
! Process that handles the card.
!
! 1: The card is read by the plc process, and is handled by a specific
! thread in the plc, which is specified in the ThreadObject attribute.
! 2: The card is read by the rt_io_comm process.
! 4: The card is handled by an application program.
!*/
Object Process $Attribute 20 18-OCT-2011 11:18:07.74
Body SysBody 18-OCT-2011 11:18:07.74
Attr PgmName = "Process"
Attr TypeRef = "pwrb:Type-IoProcessMask"
EndBody
EndObject
!/**
! @Summary Plc thread that handles the module.
! The PlcThread object of the plc thread that handles the module.
! The module is handled with the scantime of the thread.
!*/
Object ThreadObject $Attribute 21 18-OCT-2011 11:18:07.74
Body SysBody 18-OCT-2011 11:18:07.74
Attr PgmName = "ThreadObject"
Attr TypeRef = "pwrs:Type-$Objid"
EndBody
EndObject
EndObject
Object IoMethods $RtMethod 280 18-OCT-2011 11:18:07.74
Object IoCardInit $Method 281 18-OCT-2011 11:18:07.74
Body SysBody 18-OCT-2011 11:29:45.08
Attr MethodName = "Modbus_RTU_Module-IoCardInit"
EndBody
EndObject
Object IoCardRead $Method 282 18-OCT-2011 11:18:07.74
Body SysBody 18-OCT-2011 11:29:52.02
Attr MethodName = "Modbus_RTU_Module-IoCardRead"
EndBody
EndObject
Object IoCardWrite $Method 283 18-OCT-2011 11:18:07.74
Body SysBody 18-OCT-2011 11:29:58.27
Attr MethodName = "Modbus_RTU_Module-IoCardWrite"
EndBody
EndObject
EndObject
Object PostCreate $DbCallBack 284 18-OCT-2011 11:18:07.74
Body SysBody 18-OCT-2011 11:18:07.74
Attr MethodName = "BaseIOCard-PostCreate"
EndBody
EndObject
Object Template Modbus_RTU_Module 2155839488 01-JAN-1970 01:00:00.00
Body RtBody 18-OCT-2011 11:30:53.55
Attr Continous = 1
Attr ScanInterval = 1
Attr Process = 1
EndBody
EndObject
EndObject
!/**
! @Version 1.0
! @Group IO
! @Summary Server object for Modbus RTU I/O.
! Server object for Modbus RTU I/O.
!
! The defines a Modbus/RTU server, i.e. makes it possible to act as a slave
! in the communication with a Modbus/RTU master.
!
! The Server object is placed in the node hierarchy under the node object.
!
! @classlink Modbus_RTU_ServerModule otherio_modbus_rtu_servermodule.html
!*/
Object Modbus_RTU_Server $ClassDef 32 24-OCT-2011 08:03:56.99
Body SysBody 24-OCT-2011 08:03:46.50
Attr Editor = 0
Attr Method = 0
Attr Flags = 43088
EndBody
Object RtBody $ObjBodyDef 1 27-OCT-2011 08:57:12.15
Body SysBody 24-OCT-2011 08:04:01.44
Attr StructName = "Modbus_RTU_Server"
Attr NextAix = "_X61"
EndBody
!/**
! Description of the object.
!*/
Object Description $Attribute 39 24-OCT-2011 08:03:46.50
Body SysBody 24-OCT-2011 08:03:46.50
Attr PgmName = "Description"
Attr TypeRef = "pwrs:Type-$String80"
EndBody
EndObject
!/**
! Datasheet URL.
!*/
Object DataSheet $Attribute 40 24-OCT-2011 08:03:46.50
Body SysBody 24-OCT-2011 08:03:46.50
Attr PgmName = "DataSheet"
Attr TypeRef = "pwrs:Type-$URL"
EndBody
EndObject
!/**
! Current status of the server.
!*/
Object Status $Attribute 41 24-OCT-2011 08:03:46.50
Body SysBody 24-OCT-2011 08:03:46.50
Attr PgmName = "Status"
Attr Flags = 1040
Attr TypeRef = "pwrs:Type-$Status"
EndBody
EndObject
!/**
! @Summary Process that handles the card. Plc(1), rt_io_comm(2) or application process(4).
! Process that handles the server.
!
! 1: The server is read by the plc process, and is handled by a specific
! thread in the plc, which is specified in the ThreadObject attribute.
! 2: The server is read by the rt_io_comm process.
! 4: The server is handled by an application program.
!*/
Object Process $Attribute 42 24-OCT-2011 08:03:46.50
Body SysBody 24-OCT-2011 08:03:46.50
Attr PgmName = "Process"
Attr TypeRef = "pwrb:Type-IoProcessMask"
EndBody
EndObject
!/**
! @Summary Plc thread that handles the server.
! The PlcThread object of the plc thread that handles the server.
! The server is read with the scantime of the thread.
!*/
Object ThreadObject $Attribute 43 24-OCT-2011 08:03:46.50
Body SysBody 24-OCT-2011 08:03:46.50
Attr PgmName = "ThreadObject"
Attr TypeRef = "pwrs:Type-$Objid"
EndBody
EndObject
!/**
! Device name of the serial port, e.g. /dev/ttyS0.
!*/
Object Device $Attribute 53 24-OCT-2011 08:07:11.01
Body SysBody 24-OCT-2011 08:07:11.01
Attr PgmName = "Device"
Attr TypeRef = "pwrs:Type-$String40"
EndBody
EndObject
!/**
! Baud rate of the serial port.
!*/
Object Speed $Attribute 54 24-OCT-2011 08:07:11.01
Body SysBody 24-OCT-2011 08:07:11.01
Attr PgmName = "Speed"
Attr TypeRef = "pwrs:Type-$UInt32"
EndBody
EndObject
!/**
! Parity of the serial port.
!*/
Object Parity $Attribute 55 24-OCT-2011 08:07:11.01
Body SysBody 24-OCT-2011 08:07:11.01
Attr PgmName = "Parity"
Attr TypeRef = "pwrb:Type-ParityEnum"
EndBody
EndObject
!/**
! Stop bits of the serial port.
!*/
Object StopBits $Attribute 56 24-OCT-2011 08:07:11.01
Body SysBody 24-OCT-2011 08:07:11.01
Attr PgmName = "StopBits"
Attr TypeRef = "pwrb:Type-StopBitsEnum"
EndBody
EndObject
!/**
! Data bits of the serial port.
!*/
Object DataBits $Attribute 57 24-OCT-2011 08:07:11.01
Body SysBody 24-OCT-2011 08:07:11.01
Attr PgmName = "DataBits"
Attr TypeRef = "pwrb:Type-DataBitsEnum"
EndBody
EndObject
!/**
! If Yes, the server is disabled.
!*/
Object DisableServer $Attribute 45 24-OCT-2011 08:03:46.50
Body SysBody 24-OCT-2011 08:03:46.50
Attr PgmName = "DisableServer"
Attr TypeRef = "pwrb:Type-YesNoEnum"
EndBody
EndObject
!/**
! @Summary Error count of the server.
! ErrorCount will increase every cycle if status is not MB__NORMAL.
! When ErrorCount reaches the ErrorLimit all inputs are reset to zero.
!*/
Object ErrorCount $Attribute 46 24-OCT-2011 08:03:46.50
Body SysBody 24-OCT-2011 08:03:46.50
Attr PgmName = "ErrorCount"
Attr Flags = 1040
Attr TypeRef = "pwrs:Type-$UInt16"
EndBody
EndObject
!/**
! @Summary Error limit of the server.
! ErrorCount will increase every cycle if status is not MB__NORMAL.
! When ErrorCount reaches the ErrorLimit all inputs are reset to zero.
!*/
Object ErrorLimit $Attribute 47 24-OCT-2011 08:03:46.50
Body SysBody 24-OCT-2011 08:03:46.50
Attr PgmName = "ErrorLimit"
Attr TypeRef = "pwrs:Type-$UInt16"
EndBody
EndObject
!/**
! Timeout for character read.
!*/
Object CharTimeout $Attribute 48 25-OCT-2011 13:28:00.42
Body SysBody 25-OCT-2011 13:30:14.63
Attr PgmName = "CharTimeout"
Attr TypeRef = "pwrs:Type-$Float32"
EndBody
EndObject
!/**
! Not used.
!*/
Object FrameTimeout $Attribute 58 26-OCT-2011 16:59:58.07
Body SysBody 26-OCT-2011 16:59:59.48
Attr PgmName = "FrameTimeout"
Attr TypeRef = "pwrs:Type-$Float32"
EndBody
EndObject
!/**
! Received number of messages for the server.
!*/
Object RX_packets $Attribute 49 24-OCT-2011 08:03:46.50
Body SysBody 24-OCT-2011 08:03:46.50
Attr PgmName = "RX_packets"
Attr Flags = 1040
Attr TypeRef = "pwrs:Type-$UInt32"
EndBody
EndObject
!/**
! Sent number of messages from the server.
!*/
Object TX_packets $Attribute 50 24-OCT-2011 08:03:46.50
Body SysBody 24-OCT-2011 08:03:46.50
Attr PgmName = "TX_packets"
Attr Flags = 1040
Attr TypeRef = "pwrs:Type-$UInt32"
EndBody
EndObject
!/**
! @Summary Input area.
! Area where all input data is stored.
!*/
Object Inputs $Attribute 51 24-OCT-2011 08:03:46.50
Body SysBody 24-OCT-2011 08:03:46.50
Attr PgmName = "Inputs"
Attr Flags = 3090
Attr Elements = 256
Attr TypeRef = "pwrs:Type-$UInt8"
EndBody
EndObject
!/**
! @Summary Ouput area.
! Area where all output data is stored.
!*/
Object Outputs $Attribute 52 24-OCT-2011 08:03:46.50
Body SysBody 24-OCT-2011 08:03:46.50
Attr PgmName = "Outputs"
Attr Flags = 3090
Attr Elements = 256
Attr TypeRef = "pwrs:Type-$UInt8"
EndBody
EndObject
!/**
! Print debug information.
!*/
Object Debug $Attribute 60 27-OCT-2011 08:57:19.86
Body SysBody 27-OCT-2011 08:57:53.68
Attr Flags = 25167872
Attr TypeRef = "pwrs:Type-$Boolean"
EndBody
EndObject
EndObject
Object IoMethods $RtMethod 285 24-OCT-2011 08:03:46.50
Object IoRackInit $Method 286 24-OCT-2011 08:03:46.50
Body SysBody 24-OCT-2011 08:05:15.56
Attr MethodName = "Modbus_RTU_Server-IoRackInit"
EndBody
EndObject
Object IoRackClose $Method 287 24-OCT-2011 08:03:46.50
Body SysBody 24-OCT-2011 08:05:21.95
Attr MethodName = "Modbus_RTU_Server-IoRackClose"
EndBody
EndObject
Object IoRackRead $Method 288 24-OCT-2011 08:05:26.11
Body SysBody 24-OCT-2011 08:05:30.33
Attr MethodName = "Modbus_RTU_Server-IoRackRead"
EndBody
EndObject
Object IoRackWrite $Method 289 24-OCT-2011 08:03:46.50
Body SysBody 24-OCT-2011 08:05:36.10
Attr MethodName = "Modbus_RTU_Server-IoRackWrite"
EndBody
EndObject
EndObject
Object PostCreate $DbCallBack 290 24-OCT-2011 08:03:46.50
Body SysBody 24-OCT-2011 08:03:46.50
Attr MethodName = "BaseIORack-PostCreate"
EndBody
EndObject
Object Template Modbus_RTU_Server 2156101632 01-JAN-1970 01:00:00.00
Body RtBody 26-OCT-2011 18:00:51.72
Attr Process = 1
Attr Device = "/dev/ttyS0"
Attr Speed = 9600
Attr StopBits = 2
Attr DataBits = 8
Attr ErrorLimit = 100
Attr CharTimeout = 2.000000e-02
EndBody
EndObject
EndObject
!/**
! @Version 1.0
! @Group IO
! @Summary Server Module object for Modbus RTU I/O.
! Server Module object for Modbus RTU I/O.
!
! The Module object is placed as a child to a Modbus_RTU_Server object
! and is the father of channel objects that define the input and
! output area for the module.
!
! @classlink Modbus_RTU_Server otherio_modbus_rtu_server.html
!*/
Object Modbus_RTU_ServerModule $ClassDef 33 24-OCT-2011 08:04:31.37
Body SysBody 24-OCT-2011 08:04:13.86
Attr Editor = 0
Attr Method = 0
Attr Flags = 51280
EndBody
Object RtBody $ObjBodyDef 1 24-OCT-2011 08:04:13.86
Body SysBody 24-OCT-2011 08:04:37.00
Attr StructName = "Modbus_RTU_ServerModule"
Attr NextAix = "_X28"
EndBody
!/**
! Description of the object.
!*/
Object Description $Attribute 21 24-OCT-2011 08:04:13.86
Body SysBody 24-OCT-2011 08:04:13.86
Attr PgmName = "Description"
Attr TypeRef = "pwrs:Type-$String80"
EndBody
EndObject
!/**
! @Summary Address for reading registers.
! Address for reading with function code ReadHoldingRegisters.
! The value defines the starting address for the input channels
! of class ChanIi and ChanAi.
!
! Note that the address for ReadDiscreteInputs and ReadCoils are
! not affected by the ReadAddress.
!*/
Object ReadAddress $Attribute 22 24-OCT-2011 08:04:13.86
Body SysBody 24-OCT-2011 08:04:13.86
Attr PgmName = "ReadAddress"
Attr TypeRef = "pwrs:Type-$UInt32"
EndBody
EndObject
!/**
! @Summary Address for writing registers.
! Address for reading with function code WriteMultipleRegisters and
! WriteSingleRegister.
! The value defines the starting address for the output channels
! of class ChanIo and ChanAo.
!
! Note that the address for WriteSingleCoil and WriteMultipleCoils
! are not affected by the WriteAddress.
!*/
Object WriteAddress $Attribute 23 24-OCT-2011 08:04:13.86
Body SysBody 24-OCT-2011 08:04:13.86
Attr PgmName = "WriteAddress"
Attr TypeRef = "pwrs:Type-$UInt32"
EndBody
EndObject
!/**
! @Summary Unit id.
! Identification of the modbus server unit.
!*/
Object UnitId $Attribute 24 24-OCT-2011 08:04:13.86
Body SysBody 24-OCT-2011 08:04:13.86
Attr PgmName = "UnitId"
Attr TypeRef = "pwrs:Type-$UInt16"
EndBody
EndObject
!/**
! Module status.
!*/
Object Status $Attribute 25 24-OCT-2011 08:04:13.86
Body SysBody 24-OCT-2011 08:04:13.86
Attr PgmName = "Status"
Attr Flags = 1040
Attr TypeRef = "OtherIO:Type-ModbusSever_StatusEnum"
EndBody
EndObject
!/**
! @Summary Process that handles the module. Plc(1), rt_io_comm(2) or application process(4).
! Process that handles the module.
!
! 1: The module is read by the plc process, and is handled by a specific
! thread in the plc, which is specified in the ThreadObject attribute.
! 2: The module is read by the rt_io_comm process.
! 4: The module is handled by an application program.
!*/
Object Process $Attribute 26 24-OCT-2011 08:04:13.86
Body SysBody 24-OCT-2011 08:04:13.86
Attr PgmName = "Process"
Attr TypeRef = "pwrb:Type-IoProcessMask"
EndBody
EndObject
!/**
! @Summary Plc thread that handles the module.
! The PlcThread object of the plc thread that handles the module.
! The master is read with the scantime of the thread.
!*/
Object ThreadObject $Attribute 27 24-OCT-2011 08:04:13.86
Body SysBody 24-OCT-2011 08:04:13.86
Attr PgmName = "ThreadObject"
Attr TypeRef = "pwrs:Type-$Objid"
EndBody
EndObject
EndObject
Object IoMethods $RtMethod 291 24-OCT-2011 08:04:13.86
Object IoCardInit $Method 292 24-OCT-2011 08:04:13.86
Body SysBody 24-OCT-2011 08:04:48.67
Attr MethodName = "Modbus_RTU_ServerModule-IoCardInit"
EndBody
EndObject
Object IoCardRead $Method 293 24-OCT-2011 08:04:13.86
Body SysBody 24-OCT-2011 08:04:54.62
Attr MethodName = "Modbus_RTU_ServerModule-IoCardRead"
EndBody
EndObject
Object IoCardWrite $Method 294 24-OCT-2011 08:04:13.86
Body SysBody 24-OCT-2011 08:05:01.41
Attr MethodName = "Modbus_RTU_ServerModule-IoCardWrite"
EndBody
EndObject
EndObject
Object PostCreate $DbCallBack 295 24-OCT-2011 08:04:13.86
Body SysBody 24-OCT-2011 08:04:13.86
Attr MethodName = "BaseIOCard-PostCreate"
EndBody
EndObject
Object Template Modbus_RTU_ServerModule 2156363776 01-JAN-1970 01:00:00.00
Body RtBody 24-OCT-2011 08:09:15.76
Attr Process = 1
EndBody
EndObject
EndObject
Object GPIO $ClassDef 8 15-APR-2010 21:46:30.11
Body SysBody 15-APR-2010 21:46:16.74
Attr Editor = 0
......
!
! Proview Open Source Process Control.
! Copyright (C) 2005-2011 SSAB Oxelosund AB.
!
! This file is part of Proview.
!
! 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 Proview. If not, see <http://www.gnu.org/licenses/>
!
! Linking Proview statically or dynamically with other modules is
! making a combined work based on Proview. Thus, the terms and
! conditions of the GNU General Public License cover the whole
! combination.
!
! In addition, as a special exception, the copyright holders of
! Proview give you permission to, from the build function in the
! Proview Configurator, combine Proview with modules generated by the
! Proview PLC Editor to a PLC program, regardless of the license
! terms of these modules. You may copy and distribute the resulting
! combined work under the terms of your choice, provided that every
! copy of the combined work is accompanied by a complete copy of
! the source code of Proview (the version used to produce the
! combined work), being distributed under the terms of the GNU
! General Public License plus this exception.
!
! pwrb_td_stallactionenum.wb_load -- Defines the enum type StallAction
!
SObject pwrb:Type
!/**
! @Version 1.0
! @Group Types
! Enumeration for I/O stall action.
!*/
Object StallActionEnum $TypeDef 58
Body SysBody
Attr TypeRef = "pwrs:Type-$Enum"
Attr PgmName = "StallActionEnum"
EndBody
!/**
! No.
!*/
Object No $Value
Body SysBody
Attr PgmName = "No"
Attr Text = "No"
Attr Value = 0
EndBody
EndObject
!/**
! Reset inputs.
!*/
Object ResetInputs $Value
Body SysBody
Attr PgmName = "ResetInputs"
Attr Text = "Reset inputs"
Attr Value = 1
EndBody
EndObject
!/**
! Emergency break.
!*/
Object EmergencyBreak $Value
Body SysBody
Attr PgmName = "EmergencyBreak"
Attr Text = "Set emergency break"
Attr Value = 2
EndBody
EndObject
EndObject
EndSObject
......@@ -307,6 +307,17 @@ palette NavigatorPalette
class Modbus_TCP_ServerModule
}
}
menu Modbus_RTU
{
class Modbus_RTU_Master
class Modbus_RTU_Slave
class Modbus_RTU_Module
menu Server
{
class Modbus_RTU_Server
class Modbus_RTU_ServerModule
}
}
menu Hilscher_cifX
{
class Hilscher_cifX_Master
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment