Commit 185ac1f1 authored by Claes Sjofors's avatar Claes Sjofors

Modbus TCP server implemented

parent ab87999a
......@@ -3,5 +3,6 @@
071220 cs usbio Methods and objects for MotionControl USB I/O added.
080229 rk modbus New I/O-system for Modbus TCP implemented.
081016 rk modbus Added class Modbus_Master.
081016 rk modbus Added moore functionality.
081016 rk modbus Added more functionality.
090301 cs usbio Bugfix for Ai on port B. If Ai and Di/Do were mixed the Ai didn't work.
091208 cs modbus Modbus TCP Server implemented.
/*
* Proview $Id$
* Copyright (C) 2005 SSAB Oxelsund AB.
*
* 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 the program, if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* rt_io_m_mb_tcp_server.c -- io methods for Modbus/TCP Server */
#include <stdio.h>
#include <string.h>
#include <errno.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 <pthread.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_thread.h"
#include "rt_io_msg.h"
#include "rt_errh.h"
#include "rt_thread.h"
#include "co_cdh.h"
#include "co_time.h"
#include "rt_mb_msg.h"
#include "rt_io_mb_locals.h"
char rcv_buffer[65536];
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;
int idx;
} mb_sCondata;
static void mb_close_connection( io_sRack *rp, int l_idx)
{
pwr_sClass_Modbus_TCP_Server *op = (pwr_sClass_Modbus_TCP_Server *) rp->op;
io_sServerLocal* local = rp->Local;
pwr_tStatus sts;
sts = thread_Cancel( &local->connections[l_idx].t);
close( local->connections[l_idx].c_socket);
local->connections[l_idx].occupied = 0;
op->Connections--;
}
static void *mb_receive( void *data)
{
io_sRack *rp = ((mb_sCondata *)data)->rp;
int l_idx = ((mb_sCondata *)data)->idx;
io_sServerLocal* local = rp->Local;
int c_socket = local->connections[l_idx].c_socket;
pwr_sClass_Modbus_TCP_Server *op = (pwr_sClass_Modbus_TCP_Server *) rp->op;
ssize_t data_size;
rec_buf *rb;
unsigned char fc;
unsigned char exception_code;
ssize_t ssts;
int size_of_msg;
free( data);
op->Connections++;
while ( 1) {
size_of_msg = 0;
data_size = recv(c_socket, rcv_buffer, sizeof(rec_buf), 0);
if ( data_size < 0) {
op->ErrorCount++;
continue;
}
if ( data_size == 0) {
/* Disconnected */
op->Connections--;
close( c_socket);
local->connections[l_idx].occupied = 0;
errh_Error( "Connection lost for IO modbus tcp server %s, %d", rp->Name, c_socket);
return 0;
}
if ( op->DisableServer)
continue;
while ( data_size > 0) {
if (data_size < sizeof(mbap_header))
break;
op->RX_packets++;
rb = (rec_buf *) &rcv_buffer[size_of_msg];
if ( rb->head.length == 0)
break;
size_of_msg += ntohs(rb->head.length) + 6;
data_size -= ntohs(rb->head.length) + 6;
fc = (unsigned char) *rb->buf;
time_GetTime( &local->connections[l_idx].last_req_time);
exception_code = 0;
switch ( fc) {
case pwr_eModbus_FCEnum_ReadHoldingRegisters: {
io_sCard *cardp;
io_sServerModuleLocal *local_card;
pwr_sClass_Modbus_TCP_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->head.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_TCP_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.head.trans_id = rmsg->head.trans_id;
// msg.head.length = htons( sizeof(msg) - 6);
msg.head.length = htons( sizeof(msg) - sizeof(msg.buf) + quant * 2 - 6);
msg.head.unit_id = rmsg->head.unit_id;
msg.head.proto_id = rmsg->head.proto_id;
thread_MutexLock( &local->mutex);
memcpy( msg.buf, (char *)local_card->output_area + addr, quant * 2);
thread_MutexUnlock( &local->mutex);
ssts = send( c_socket, &msg, ntohs(msg.head.length) + 6, MSG_DONTWAIT);
if (ssts < 0) {
op->Connections--;
close(c_socket);
local->connections[l_idx].occupied = 0;
errh_Error( "Connection lost for IO modbus tcp server %s, %d", rp->Name, c_socket);
return 0;
}
op->TX_packets++;
break;
}
case pwr_eModbus_FCEnum_ReadCoils:
case pwr_eModbus_FCEnum_ReadDiscreteInputs: {
io_sCard *cardp;
io_sServerModuleLocal *local_card;
pwr_sClass_Modbus_TCP_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->head.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_TCP_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.head.trans_id = rmsg->head.trans_id;
// msg.head.length = htons( sizeof(msg) - 6);
msg.head.length = htons( sizeof(msg) - sizeof(msg.buf) + bytes - 6);
msg.head.unit_id = rmsg->head.unit_id;
msg.head.proto_id = rmsg->head.proto_id;
thread_MutexLock( &local->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->mutex);
ssts = send( c_socket, &msg, ntohs(msg.head.length) + 6, MSG_DONTWAIT);
if (ssts < 0) {
op->Connections--;
close(c_socket);
local->connections[l_idx].occupied = 0;
errh_Error( "Connection lost for IO modbus tcp server %s, %d", rp->Name, c_socket);
return 0;
}
op->TX_packets++;
break;
}
case pwr_eModbus_FCEnum_WriteSingleRegister: {
io_sCard *cardp;
io_sServerModuleLocal *local_card;
pwr_sClass_Modbus_TCP_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->head.unit_id;
/* Check the address */
found = 0;
for ( cardp = rp->cardlist; cardp; cardp = cardp->next) {
mp = (pwr_sClass_Modbus_TCP_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->mutex);
memcpy( (char *)local_card->input_area + addr, &rmsg->value, 2);
thread_MutexUnlock( &local->mutex);
msg.fc = fc;
msg.addr = rmsg->addr;
msg.value = rmsg->value;
msg.head.trans_id = rmsg->head.trans_id;
msg.head.length = htons( sizeof(msg) - 6);
msg.head.unit_id = rmsg->head.unit_id;
msg.head.proto_id = rmsg->head.proto_id;
ssts = send( c_socket, &msg, sizeof(msg), MSG_DONTWAIT);
if (ssts < 0) {
op->Connections--;
close(c_socket);
local->connections[l_idx].occupied = 0;
errh_Error( "Connection lost for IO modbus tcp server %s, %d", rp->Name, c_socket);
return 0;
}
op->TX_packets++;
break;
}
case pwr_eModbus_FCEnum_WriteMultipleRegisters: {
io_sCard *cardp;
io_sServerModuleLocal *local_card;
pwr_sClass_Modbus_TCP_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->head.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_TCP_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->mutex);
memcpy( (char *)local_card->input_area + addr, rmsg->reg, quant * 2);
thread_MutexUnlock( &local->mutex);
msg.fc = fc;
msg.addr = rmsg->addr;
msg.quant = rmsg->quant;
msg.head.trans_id = rmsg->head.trans_id;
msg.head.length = htons( sizeof(msg) - 6);
msg.head.unit_id = rmsg->head.unit_id;
msg.head.proto_id = rmsg->head.proto_id;
ssts = send( c_socket, &msg, sizeof(msg), MSG_DONTWAIT);
if (ssts < 0) {
op->Connections--;
close(c_socket);
local->connections[l_idx].occupied = 0;
errh_Error( "Connection lost for IO modbus tcp server %s, %d", rp->Name, c_socket);
return 0;
}
op->TX_packets++;
break;
}
case pwr_eModbus_FCEnum_WriteSingleCoil: {
io_sCard *cardp;
io_sServerModuleLocal *local_card;
pwr_sClass_Modbus_TCP_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);
short value = ntohs( rmsg->value);
unsigned char unit_id = rmsg->head.unit_id;
/* Check the address */
found = 0;
for ( cardp = rp->cardlist; cardp; cardp = cardp->next) {
mp = (pwr_sClass_Modbus_TCP_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);
thread_MutexLock( &local->mutex);
if ( value)
*((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->mutex);
msg.fc = fc;
msg.addr = rmsg->addr;
msg.value = rmsg->value;
msg.head.trans_id = rmsg->head.trans_id;
msg.head.length = htons( sizeof(msg) - 6);
msg.head.unit_id = rmsg->head.unit_id;
msg.head.proto_id = rmsg->head.proto_id;
ssts = send( c_socket, &msg, sizeof(msg), MSG_DONTWAIT);
if (ssts < 0) {
op->Connections--;
close(c_socket);
local->connections[l_idx].occupied = 0;
errh_Error( "Connection lost for IO modbus tcp server %s, %d", rp->Name, c_socket);
return 0;
}
op->TX_packets++;
break;
}
case pwr_eModbus_FCEnum_WriteMultipleCoils: {
io_sCard *cardp;
io_sServerModuleLocal *local_card;
pwr_sClass_Modbus_TCP_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->head.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_TCP_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->di_offset > local_card->input_size ||
offs + bytes > local_card->di_size) {
exception_code = 2;
break;
}
thread_MutexLock( &local->mutex);
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->mutex);
msg.fc = fc;
msg.addr = rmsg->addr;
msg.quant = rmsg->quant;
msg.head.trans_id = rmsg->head.trans_id;
msg.head.length = htons( sizeof(msg) - 6);
msg.head.unit_id = rmsg->head.unit_id;
msg.head.proto_id = rmsg->head.proto_id;
ssts = send( c_socket, &msg, sizeof(msg), MSG_DONTWAIT);
if (ssts < 0) {
op->Connections--;
close(c_socket);
local->connections[l_idx].occupied = 0;
errh_Error( "Connection lost for IO modbus tcp server %s, %d", rp->Name, c_socket);
return 0;
}
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.head.trans_id = rmsg->head.trans_id;
msg.head.length = htons( sizeof(msg) - sizeof(msg.list) + i - 6);
msg.head.unit_id = rmsg->head.unit_id;
msg.head.proto_id = rmsg->head.proto_id;
ssts = send( c_socket, &msg, ntohs(msg.head.length) + 6, MSG_DONTWAIT);
if (ssts < 0) {
op->Connections--;
close(c_socket);
local->connections[l_idx].occupied = 0;
errh_Error( "Connection lost for IO modbus tcp server %s, %d", rp->Name, c_socket);
return 0;
}
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.head.trans_id = rb->head.trans_id;
rsp_f.head.length = htons( sizeof(rsp_f) - 6);
rsp_f.head.unit_id = rb->head.unit_id;
ssts = send( c_socket, &rsp_f, sizeof(rsp_f), MSG_DONTWAIT);
if (ssts < 0) {
op->Connections--;
close(c_socket);
local->connections[l_idx].occupied = 0;
errh_Error( "Connection lost for IO modbus tcp server %s, %d", rp->Name, c_socket);
return 0;
}
op->TX_packets++;
}
}
}
return 0;
}
static void *mb_connect( void *arg)
{
io_sRack *rp = (io_sRack *)arg;
io_sServerLocal* local = rp->Local;
int sts;
pwr_sClass_Modbus_TCP_Server *op;
struct sockaddr_in r_addr;
socklen_t r_addr_len;
int c_socket;
mb_sCondata *condata;
int idx;
int found;
int i;
op = (pwr_sClass_Modbus_TCP_Server *) rp->op;
while ( 1) {
/* Wait for client connect request */
r_addr_len = sizeof(r_addr);
c_socket = accept( local->s, (struct sockaddr *) &r_addr, &r_addr_len);
if ( c_socket < 0) {
errh_Error( "Error accept IO modbus tcp server %s, %d", rp->Name, local->s);
continue;
}
if ( op->DisableServer)
continue;
errh_Info( "Connection accepted for IO modbus tcp server %s, %d", rp->Name, c_socket);
/* Close other connections to this address */
for ( i = 0; i < MB_MAX_CONNECTIONS; i++) {
if ( local->connections[i].occupied &&
r_addr_len == local->connections[i].addrlen &&
r_addr.sin_family == local->connections[i].addr.sin_family &&
memcmp( &r_addr.sin_addr, &local->connections[i].addr.sin_addr, sizeof(r_addr.sin_addr)) == 0) {
mb_close_connection( rp, i);
}
}
/* Find next empty in connection list */
found = 0;
for ( i = 0; i < MB_MAX_CONNECTIONS; i++) {
if ( !local->connections[i].occupied) {
found = 1;
idx = i;
break;
}
}
if ( !found) {
/* Remove the oldest connection */
int oldest_idx = 0;
for ( i = 1; i < MB_MAX_CONNECTIONS; i++) {
if ( time_Acomp( &local->connections[i].last_req_time, &local->connections[oldest_idx].last_req_time) < 0)
oldest_idx = i;
}
mb_close_connection( rp, oldest_idx);
errh_Info( "Connection closed, IO modbus tcp server %s, %d", rp->Name, local->s);
idx = oldest_idx;
}
local->connections[idx].c_socket = c_socket;
local->connections[idx].occupied = 1;
time_GetTime( &local->connections[idx].last_req_time);
local->connections[idx].addrlen = r_addr_len;
memcpy( &local->connections[idx].addr, &r_addr, r_addr_len);
/* Create a thread for this connection */
condata = (mb_sCondata *) malloc( sizeof(mb_sCondata));
condata->rp = rp;
condata->idx = idx;
sts = thread_Create( &local->connections[idx].t, 0, mb_receive, (void *)condata);
if ( EVEN(sts)) {
local->connections[idx].occupied = 0;
errh_Error( "Error creating thread IO modbus tcp server %s, %d", rp->Name, local->s);
free( condata);
continue;
}
}
return 0;
}
/*----------------------------------------------------------------------------*\
Init method for the Modbus/TCP server
\*----------------------------------------------------------------------------*/
static pwr_tStatus IoRackInit (
io_tCtx ctx,
io_sAgent *ap,
io_sRack *rp
)
{
io_sServerLocal *local;
pthread_t thread;
pwr_tOName name;
pwr_tStatus sts;
pwr_sClass_Modbus_TCP_Server *op;
int i;
unsigned short port;
op = (pwr_sClass_Modbus_TCP_Server *) rp->op;
op->Connections = 0;
port = op->Port == 0 ? 502 : op->Port;
sts = gdh_ObjidToName(rp->Objid, (char *) &name, sizeof(name), cdh_mNName);
errh_Info( "Init of Modbus TCP Server %s", name);
rp->Local = calloc(1, sizeof(io_sServerLocal));
local = rp->Local;
if ( op->DisableServer)
return IO__SUCCESS;
/* Create socket, store in local struct */
uid_t ruid;
ruid = getuid();
printf( "ruid: %d\n", ruid);
local->s = socket(AF_INET, SOCK_STREAM, 0);
if (local->s < 0) {
errh_Error( "Error creating socket for IO modbus tcp server %s, %d", rp->Name, local->s);
return 0;
}
local->loc_addr.sin_family = AF_INET;
local->loc_addr.sin_port = htons(port);
for ( i = 0; i < 10; i++) {
sts = bind( local->s, (struct sockaddr *) &local->loc_addr, sizeof(local->loc_addr));
if ( sts == 0)
break;
perror( "Modbus TCP Bind socket failure, retrying... ");
sleep( 10);
}
if ( sts != 0) {
printf( "Modbus TCP Bind socket failure, exiting");
errh_Error( "Error bind socket to port for IO modbus tcp server %s, %d", rp->Name, local->s);
return 0;
}
errh_Info( "Modbus TCP Sever bind to port %d, %s", port, name);
sts = listen( local->s, 16);
sts = thread_MutexInit( &local->mutex);
if ( EVEN(sts)) return sts;
/* Create a thread that listens for connections */
sts = pthread_create( &thread, NULL, mb_connect, (void *)rp);
if ( sts != 0) return sts;
sts = mb_init_channels( ctx, ap, rp);
if ( EVEN(sts)) return sts;
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_TCP_Server *op;
pwr_sClass_Modbus_TCP_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_TCP_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_TCP_ServerModule:
mp = (pwr_sClass_Modbus_TCP_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 TCP server
\*----------------------------------------------------------------------------*/
static pwr_tStatus IoRackRead (
io_tCtx ctx,
io_sAgent *ap,
io_sRack *rp
)
{
return IO__SUCCESS;
}
/*----------------------------------------------------------------------------*\
Write method for the Modbus_TCP 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;
int i;
for ( i = 1; i < MB_MAX_CONNECTIONS; i++) {
if ( local->connections[i].occupied)
mb_close_connection( rp, i);
}
close( local->s);
return IO__SUCCESS;
}
/*----------------------------------------------------------------------------*\
Every method to be exported to the workbench should be registred here.
\*----------------------------------------------------------------------------*/
pwr_dExport pwr_BindIoMethods(Modbus_TCP_Server) = {
pwr_BindIoMethod(IoRackInit),
pwr_BindIoMethod(IoRackRead),
pwr_BindIoMethod(IoRackWrite),
pwr_BindIoMethod(IoRackClose),
pwr_NullMethod
};
/*
* Proview $Id$
* Copyright (C) 2005 SSAB Oxelsund AB.
*
* 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 the program, if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#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_locals.h"
#include "co_time.h"
/*----------------------------------------------------------------------------*\
Init method for the Modbus module
\*----------------------------------------------------------------------------*/
static pwr_tStatus IoCardInit (
io_tCtx ctx,
io_sAgent *ap,
io_sRack *rp,
io_sCard *cp
)
{
io_sServerModuleLocal *local;
pwr_sClass_Modbus_TCP_ServerModule *op;
int i;
op = (pwr_sClass_Modbus_TCP_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 TCP 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_TCP_ServerModule *op;
pwr_sClass_Modbus_TCP_Server *server;
printf( "Module: Read method\n");
op = (pwr_sClass_Modbus_TCP_ServerModule *) cp->op;
local = (io_sServerModuleLocal *) cp->Local;
server = (pwr_sClass_Modbus_TCP_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_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 Pb 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_TCP_ServerModule *op;
pwr_sClass_Modbus_TCP_Server *server;
printf( "Module: Write method\n");
op = (pwr_sClass_Modbus_TCP_ServerModule *) cp->op;
local = (io_sServerModuleLocal *) cp->Local;
server = (pwr_sClass_Modbus_TCP_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_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_TCP_ServerModule) = {
pwr_BindIoMethod(IoCardInit),
pwr_BindIoMethod(IoCardRead),
pwr_BindIoMethod(IoCardWrite),
pwr_NullMethod
};
......@@ -19,7 +19,6 @@
/* rt_io_m_pb_dp_slave.c -- io methods for a profibus DP slave */
#pragma pack(1)
#include <stdio.h>
#include <string.h>
......@@ -62,12 +61,14 @@ static int connect_slave( io_sRackLocal *local, io_sRack *rp)
fd_set fdr; /* For select call */
fd_set fdw; /* For select call */
struct timeval tv;
unsigned short port;
time_GetTimeMonotonic( &local->last_try_connect_time);
op = (pwr_sClass_Modbus_TCP_Slave *) rp->op;
/* Create socket, store in local struct */
port = op->Port == 0 ? 502 : op->Port;
local->s = socket(AF_INET, SOCK_STREAM, 0);
if (local->s < 0) {
......@@ -84,7 +85,7 @@ static int connect_slave( io_sRackLocal *local, io_sRack *rp)
/* Initialize remote address structure */
local->rem_addr.sin_family = AF_INET;
local->rem_addr.sin_port = htons(502);
local->rem_addr.sin_port = htons(port);
local->rem_addr.sin_addr.s_addr = inet_addr((char *) &(op->Address));
/* Connect to remote address */
......@@ -139,7 +140,7 @@ pwr_tStatus mb_recv_data(io_sRackLocal *local,
pwr_tCid cid;
unsigned char fc;
short int trans_id;
short int size_of_msg = 0;
short int size_of_msg;
/* Receive answer */
......@@ -153,10 +154,18 @@ pwr_tStatus mb_recv_data(io_sRackLocal *local,
FD_SET(local->s, &fdw);
FD_SET(local->s, &fde);
size_of_msg = 0;
tv.tv_sec = 0;
tv.tv_usec = 0;
sts = select(32, &fdr, &fdw, &fde, &tv);
if (sts < 0) {
sp->Status = MB__CONNLOST;
close(local->s);
errh_Error( "Connection lost to modbus slave, %s", rp->Name);
return IO__SUCCESS;
}
if (!(FD_ISSET(local->s, &fdw))) {
sp->Status = MB__CONNDOWN;
......@@ -182,6 +191,7 @@ pwr_tStatus mb_recv_data(io_sRackLocal *local,
if (sts < 0) {
sp->Status = MB__CONNLOST;
close(local->s);
errh_Error( "Connection lost to modbus slave, %s", rp->Name);
return IO__SUCCESS;
}
......@@ -201,6 +211,7 @@ pwr_tStatus mb_recv_data(io_sRackLocal *local,
if (data_size < 0) {
sp->Status = MB__CONNLOST;
close(local->s);
errh_Error( "Connection lost to modbus slave, %s", rp->Name);
return IO__SUCCESS;
}
......@@ -341,9 +352,7 @@ pwr_tStatus mb_send_data(io_sRackLocal *local,
if (!mp->Continous && !mp->SendOp) {
break;
}
mp->SendOp = FALSE;
local_card = cardp->Local;
if (mask & mb_mSendMask_ReadReq) {
......@@ -352,6 +361,8 @@ pwr_tStatus mb_send_data(io_sRackLocal *local,
case pwr_eModbus_FCEnum_ReadDiscreteInputs: {
read_req rr;
mp->SendOp = FALSE;
local->trans_id++;
local_card->trans_id = local->trans_id;
......@@ -361,7 +372,8 @@ pwr_tStatus mb_send_data(io_sRackLocal *local,
rr.head.unit_id = mp->UnitId;
rr.fc = mp->FunctionCode;
rr.addr = htons(mp->Address);
rr.quant = ntohs(local_card->input_size * 8);
rr.quant = htons(local_card->no_di);
// rr.quant = ntohs(local_card->input_size * 8);
sts = send(local->s, &rr, sizeof(read_req), MSG_DONTWAIT);
if (sts < 0) {
......@@ -380,6 +392,8 @@ pwr_tStatus mb_send_data(io_sRackLocal *local,
case pwr_eModbus_FCEnum_ReadInputRegisters: {
read_req rr;
mp->SendOp = FALSE;
local->trans_id++;
local_card->trans_id = local->trans_id;
......@@ -411,6 +425,8 @@ pwr_tStatus mb_send_data(io_sRackLocal *local,
case pwr_eModbus_FCEnum_WriteSingleCoil: {
write_single_req wsr;
mp->SendOp = FALSE;
local->trans_id++;
local_card->trans_id = local->trans_id;
......@@ -428,6 +444,10 @@ pwr_tStatus mb_send_data(io_sRackLocal *local,
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 = send(local->s, &wsr, ntohs(wsr.head.length) + 6, MSG_DONTWAIT);
......@@ -445,6 +465,8 @@ pwr_tStatus mb_send_data(io_sRackLocal *local,
case pwr_eModbus_FCEnum_WriteMultipleCoils: {
write_coils_req wcr;
mp->SendOp = FALSE;
local->trans_id++;
local_card->trans_id = local->trans_id;
......@@ -455,7 +477,8 @@ pwr_tStatus mb_send_data(io_sRackLocal *local,
wcr.head.unit_id = mp->UnitId;
wcr.fc = mp->FunctionCode;
wcr.addr = htons(mp->Address);
wcr.quant = ntohs((local_card->output_size) * 8);
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);
......@@ -474,6 +497,8 @@ pwr_tStatus mb_send_data(io_sRackLocal *local,
case pwr_eModbus_FCEnum_WriteMultipleRegisters: {
write_reg_req wrr;
mp->SendOp = FALSE;
local->trans_id++;
local_card->trans_id = local->trans_id;
......@@ -539,6 +564,8 @@ static pwr_tStatus IoRackInit (
short output_counter;
short card_input_counter;
short card_output_counter;
short no_di;
short no_do;
pwr_sClass_Modbus_TCP_Slave *op;
pwr_sClass_Modbus_Module *mp;
char name[196];
......@@ -596,6 +623,8 @@ static pwr_tStatus IoRackInit (
card_output_counter = 0;
latent_input_counter = 0;
latent_output_counter = 0;
no_di = 0;
no_do = 0;
/* From v4.1.3 we can have subclasses, find the super class */
......@@ -648,6 +677,7 @@ static pwr_tStatus IoRackInit (
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);
no_di++;
// printf("Di channel found in %s, Number %d, Offset %d\n", cardp->Name, chan_di->Number, chanp->offset);
break;
......@@ -696,6 +726,7 @@ static pwr_tStatus IoRackInit (
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);
no_do++;
// printf("Do channel found in %s, Number %d, Offset %d\n", cardp->Name, chan_do->Number, chanp->offset);
break;
......@@ -727,6 +758,8 @@ static pwr_tStatus IoRackInit (
local_card->input_size = card_input_counter + latent_input_counter;
local_card->output_size = card_output_counter + latent_output_counter;
local_card->no_di = no_di;
local_card->no_do = no_do;
cardp = cardp->next;
}
......@@ -757,7 +790,7 @@ static pwr_tStatus IoRackRead (
sp = (pwr_sClass_Modbus_TCP_Slave *) rp->op;
if (sp->Status == MB__CONNDOWN && sp->DisableSlave != 1) {
if (((sp->Status == MB__CONNDOWN) || (sp->Status == MB__CONNLOST)) && sp->DisableSlave != 1) {
/* Reconnect */
time_GetTimeMonotonic( &now);
......
......@@ -58,6 +58,8 @@
#define PB_UDATA_DIAG 1
#define MB_MAX_CONNECTIONS 20
typedef pwr_tMask mb_tSendMask;
typedef enum {
......@@ -93,6 +95,43 @@ typedef struct {
short int no_do;
} io_sCardLocal;
typedef struct {
pwr_tTime last_req_time;
thread_s t;
int c_socket;
struct sockaddr_in addr;
socklen_t addrlen;
int occupied;
} io_sServerConnection;
typedef struct {
int initialized;
int s;
int current_socket;
short int trans_id;
struct sockaddr_in loc_addr; /* Remote socket description */
int input_size;
int output_size;
thread_sMutex mutex;
io_sServerConnection connections[MB_MAX_CONNECTIONS];
} 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
{
......@@ -145,6 +184,14 @@ typedef struct _write_coils_req {
unsigned char reg[250];
} write_coils_req;
typedef struct _read_dev_id_req {
mbap_header head;
unsigned char fc;
unsigned char mei_type;
unsigned char id_code;
unsigned char object_id;
} read_dev_id_req;
typedef struct _res_write {
unsigned char fc;
short int addr;
......@@ -163,6 +210,45 @@ typedef struct _res_fault {
unsigned char ec;
} res_fault;
typedef struct _rsp_fault {
mbap_header head;
unsigned char fc;
unsigned char ec;
} rsp_fault;
typedef struct _rsp_read {
mbap_header head;
unsigned char fc;
unsigned char bc;
short int buf[250];
} rsp_read;
typedef struct _rsp_write {
mbap_header head;
unsigned char fc;
short int addr;
short int quant;
} rsp_write;
typedef struct _rsp_single_write {
mbap_header head;
unsigned char fc;
short int addr;
short int value;
} rsp_single_write;
typedef struct _rsp_dev_id {
mbap_header head;
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];
} rsp_dev_id;
#pragma pack(0)
pwr_tStatus mb_recv_data(io_sRackLocal *local,
......
......@@ -3,3 +3,5 @@ MotionControl_USBIO
Modbus_TCP_Slave
Modbus_Module
Modbus_Master
Modbus_TCP_Server
Modbus_TCP_ServerModule
Volume OtherIO $ClassVolume 0.0.250.10
Body SysBody 01-JAN-1970 01:00:00.00
Attr NextOix = "_X60"
Attr NextCix = "_X6"
Attr NextTix[0] = "_X4"
Attr NextOix = "_X77"
Attr NextCix = "_X8"
Attr NextTix[0] = "_X5"
EndBody
Object Type $TypeHier 1 15-NOV-2007 14:35:37.90
Object MotionControl_StatusEnum $TypeDef 1 15-NOV-2007 14:36:24.17
......@@ -176,6 +176,13 @@ Volume OtherIO $ClassVolume 0.0.250.10
Attr Value = 5
EndBody
EndObject
Object WriteSingleRegister $Value 77 04-DEC-2009 16:09:01.59
Body SysBody 04-DEC-2009 16:09:09.77
Attr Text = "WriteSingleRegister"
Attr PgmName = "WriteSingleRegister"
Attr Value = 6
EndBody
EndObject
Object WriteMultipleCoils $Value 36 07-FEB-2008 15:57:24.44
Body SysBody 07-FEB-2008 15:57:51.21
Attr Text = "WriteMultipleCoils"
......@@ -238,6 +245,60 @@ Volume OtherIO $ClassVolume 0.0.250.10
EndBody
EndObject
EndObject
Object ModbusSever_StatusEnum $TypeDef 4 25-NOV-2009 11:10:38.85
Body SysBody 25-NOV-2009 11:07:36.39
Attr TypeRef = "pwrs:Type-$Enum"
Attr Elements = 1
EndBody
Object OK $Value 70 25-NOV-2009 11:07:36.39
Body SysBody 25-NOV-2009 11:07:36.39
Attr Text = "OK"
Attr PgmName = "OK"
EndBody
EndObject
Object IllegalFunctionCode $Value 71 25-NOV-2009 11:08:32.76
Body SysBody 25-NOV-2009 11:08:35.79
Attr Text = "IllegalFunctionCode"
Attr PgmName = "IllegalFunctionCode"
Attr Value = 1
EndBody
EndObject
Object IllegalDataAddress $Value 72 25-NOV-2009 11:07:36.39
Body SysBody 25-NOV-2009 11:07:36.39
Attr Text = "IllegalDataAddress"
Attr PgmName = "IllegalDataAddress"
Attr Value = 2
EndBody
EndObject
Object IllegalDataValue $Value 73 25-NOV-2009 11:07:36.39
Body SysBody 25-NOV-2009 11:07:36.39
Attr Text = "IllegalDataValue"
Attr PgmName = "IllegalDataValue"
Attr Value = 3
EndBody
EndObject
Object ServerFailure $Value 74 25-NOV-2009 11:08:55.88
Body SysBody 25-NOV-2009 11:08:58.05
Attr Text = "ServerFailure"
Attr PgmName = "ServerFailure"
Attr Value = 4
EndBody
EndObject
Object Acknowledge $Value 75 25-NOV-2009 11:09:36.94
Body SysBody 25-NOV-2009 11:09:39.43
Attr Text = "Acknowledge"
Attr PgmName = "Acknowledge"
Attr Value = 5
EndBody
EndObject
Object SeverBusy $Value 76 25-NOV-2009 11:09:52.33
Body SysBody 25-NOV-2009 11:09:58.88
Attr Text = "SeverBusy"
Attr PgmName = "SeverBusy"
Attr Value = 6
EndBody
EndObject
EndObject
EndObject
Object Class $ClassHier 2 15-NOV-2007 14:35:40.72
!/**
......@@ -505,7 +566,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 = "_X19"
Attr NextAix = "_X20"
EndBody
!/**
! Description of slave
......@@ -531,8 +592,9 @@ Volume OtherIO $ClassVolume 0.0.250.10
! Status of the slave. Shows if tcp-link to slave is up or not.
!*/
Object Status $Attribute 3 08-FEB-2008 10:29:48.44
Body SysBody 08-FEB-2008 10:30:23.06
Body SysBody 04-DEC-2009 17:14:32.80
Attr PgmName = "Status"
Attr Flags = 1040
Attr TypeRef = "pwrs:Type-$Status"
EndBody
EndObject
......@@ -572,6 +634,13 @@ Volume OtherIO $ClassVolume 0.0.250.10
Attr TypeRef = "pwrs:Type-$String32"
EndBody
EndObject
Object Port $Attribute 19 04-DEC-2009 17:22:45.73
Body SysBody 04-DEC-2009 17:23:01.72
Attr PgmName = "Port"
Attr Flags = 16777216
Attr TypeRef = "pwrs:Type-$UInt32"
EndBody
EndObject
!/**
! @Summary Flag that disables the slave.
! Flag that disables the initialization of the slave, if initialized turns off i/o-handling.
......@@ -588,8 +657,9 @@ Volume OtherIO $ClassVolume 0.0.250.10
! When ErrorCount reaches the ErrorLimit all inputs are reset to zero.
!*/
Object ErrorCount $Attribute 7 08-FEB-2008 10:50:15.18
Body SysBody 08-FEB-2008 10:55:49.84
Body SysBody 04-DEC-2009 17:14:50.70
Attr PgmName = "ErrorCount"
Attr Flags = 1040
Attr TypeRef = "pwrs:Type-$UInt16"
EndBody
EndObject
......@@ -612,8 +682,9 @@ Volume OtherIO $ClassVolume 0.0.250.10
! try to reconnect at this cylicity.
!*/
Object ReconnectCount $Attribute 9 08-FEB-2008 10:56:12.51
Body SysBody 08-FEB-2008 10:56:17.20
Body SysBody 04-DEC-2009 17:15:01.53
Attr PgmName = "ReconnectCount"
Attr Flags = 1040
Attr TypeRef = "pwrs:Type-$UInt16"
EndBody
EndObject
......@@ -657,8 +728,9 @@ Volume OtherIO $ClassVolume 0.0.250.10
! Received number of messages from slave.
!*/
Object RX_packets $Attribute 11 08-FEB-2008 10:57:16.79
Body SysBody 08-FEB-2008 10:57:21.35
Body SysBody 04-DEC-2009 17:15:16.28
Attr PgmName = "RX_packets"
Attr Flags = 1040
Attr TypeRef = "pwrs:Type-$UInt32"
EndBody
EndObject
......@@ -667,8 +739,9 @@ Volume OtherIO $ClassVolume 0.0.250.10
! Sent number of messages to slave.
!*/
Object TX_packets $Attribute 12 08-FEB-2008 10:57:31.03
Body SysBody 08-FEB-2008 10:57:34.53
Body SysBody 04-DEC-2009 17:15:24.38
Attr PgmName = "TX_packets"
Attr Flags = 1040
Attr TypeRef = "pwrs:Type-$UInt32"
EndBody
EndObject
......@@ -765,7 +838,7 @@ Volume OtherIO $ClassVolume 0.0.250.10
! 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
......@@ -850,19 +923,10 @@ Volume OtherIO $ClassVolume 0.0.250.10
Attr TypeRef = "pwrs:Type-$UInt16"
EndBody
EndObject
!/**
! @Summary Status of the module.
! Status of the module. The status can be any of:
! OK
! IllegalFunction
! IllegalDataAddress
! IllegalDataValue
! SlaveServiceFailure
! Unknown
!*/
Object Status $Attribute 7 08-FEB-2008 11:20:34.93
Body SysBody 08-FEB-2008 11:31:11.41
Body SysBody 04-DEC-2009 17:15:47.85
Attr PgmName = "Status"
Attr Flags = 1040
Attr TypeRef = "OtherIO:Type-ModbusModule_StatusEnum"
EndBody
EndObject
......@@ -1032,5 +1096,345 @@ Volume OtherIO $ClassVolume 0.0.250.10
EndBody
EndObject
EndObject
!/**
! @Version 1.0
! @Group IO
! @Summary Server object for Modbus TCP I/O.
! Server object for Modbus TCP I/O.
!
! The defines a Modbus/TCP server, i.e. makes it possible to act as a slave
! in the communication with a Modbus/TCP master.
!
! The Server object is placed in the node hierarchy under the node object.
!
! @classlink Modbus_TCP_ServerModule otherio_modbus_tcp_servermodule.html
!*/
Object Modbus_TCP_Server $ClassDef 6 25-NOV-2009 10:32:40.64
Body SysBody 25-NOV-2009 10:30:31.66
Attr Editor = 0
Attr Method = 0
Attr Flags = 8272
EndBody
Object RtBody $ObjBodyDef 1 25-NOV-2009 10:30:31.66
Body SysBody 25-NOV-2009 10:32:51.18
Attr StructName = "Modbus_TCP_Server"
Attr NextAix = "_X39"
EndBody
!/**
! Description of the object.
!*/
Object Description $Attribute 19 25-NOV-2009 10:30:31.66
Body SysBody 25-NOV-2009 10:30:31.66
Attr PgmName = "Description"
Attr TypeRef = "pwrs:Type-$String80"
EndBody
EndObject
!/**
! Datasheet URL.
!*/
Object DataSheet $Attribute 20 25-NOV-2009 10:30:31.66
Body SysBody 25-NOV-2009 10:30:31.66
Attr PgmName = "DataSheet"
Attr TypeRef = "pwrs:Type-$URL"
EndBody
EndObject
!/**
! Current status of the server.
!*/
Object Status $Attribute 21 25-NOV-2009 10:30:31.66
Body SysBody 04-DEC-2009 17:14:06.15
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 22 25-NOV-2009 10:30:31.66
Body SysBody 25-NOV-2009 10:30:31.66
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 23 25-NOV-2009 10:30:31.66
Body SysBody 25-NOV-2009 10:30:31.66
Attr PgmName = "ThreadObject"
Attr TypeRef = "pwrs:Type-$Objid"
EndBody
EndObject
!/**
! @Summary Optional port number.
! Optional port number.
! By default the server listens to the Modbus TCP port 502.
! If another port should be used for the communication, it can be
! specified here.
!*/
Object Port $Attribute 38 04-DEC-2009 16:56:46.71
Body SysBody 04-DEC-2009 16:56:55.46
Attr PgmName = "Port"
Attr TypeRef = "pwrs:Type-$UInt32"
EndBody
EndObject
!/**
! If Yes, the server is disabled.
!*/
Object DisableServer $Attribute 25 25-NOV-2009 10:33:08.29
Body SysBody 25-NOV-2009 10:33:10.93
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 26 25-NOV-2009 10:30:31.66
Body SysBody 04-DEC-2009 16:55:35.20
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 27 25-NOV-2009 10:30:31.66
Body SysBody 25-NOV-2009 10:30:31.66
Attr PgmName = "ErrorLimit"
Attr TypeRef = "pwrs:Type-$UInt16"
EndBody
EndObject
!/**
! Number of current connections.
!*/
Object Connections $Attribute 31 25-NOV-2009 11:03:25.72
Body SysBody 25-NOV-2009 11:04:00.16
Attr PgmName = "Connections"
Attr Flags = 1040
Attr TypeRef = "pwrs:Type-$UInt32"
EndBody
EndObject
!/**
! Received number of messages for the server.
!*/
Object RX_packets $Attribute 32 25-NOV-2009 10:30:31.66
Body SysBody 04-DEC-2009 16:55:52.73
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 33 25-NOV-2009 10:30:31.66
Body SysBody 04-DEC-2009 16:56:00.02
Attr PgmName = "TX_packets"
Attr Flags = 1040
Attr TypeRef = "pwrs:Type-$UInt32"
EndBody
EndObject
!/**
! @Summary Input area.
! Area where alla input data is stored.
!*/
Object Inputs $Attribute 36 27-NOV-2009 09:42:27.83
Body SysBody 27-NOV-2009 09:42:46.12
Attr PgmName = "Inputs"
Attr Flags = 3090
Attr Elements = 256
Attr TypeRef = "pwrs:Type-$UInt8"
EndBody
EndObject
!/**
! @Summary Ouput area.
! Area where alla output data is stored.
!*/
Object Outputs $Attribute 37 27-NOV-2009 09:42:27.83
Body SysBody 27-NOV-2009 09:43:03.16
Attr PgmName = "Outputs"
Attr Flags = 3090
Attr Elements = 256
Attr TypeRef = "pwrs:Type-$UInt8"
EndBody
EndObject
EndObject
Object IoMethods $RtMethod 61 25-NOV-2009 10:30:31.66
Object IoRackInit $Method 62 25-NOV-2009 10:30:31.66
Body SysBody 25-NOV-2009 10:34:14.57
Attr MethodName = "Modbus_TCP_Server-IoRackInit"
EndBody
EndObject
Object IoRackClose $Method 63 25-NOV-2009 10:30:31.66
Body SysBody 25-NOV-2009 10:34:23.88
Attr MethodName = "Modbus_TCP_Server-IoRackClose"
EndBody
EndObject
Object IoRackRead $Method 64 25-NOV-2009 10:30:31.66
Body SysBody 25-NOV-2009 10:34:31.89
Attr MethodName = "Modbus_TCP_Server-IoRackRead"
EndBody
EndObject
Object IoRackWrite $Method 65 25-NOV-2009 10:30:31.66
Body SysBody 25-NOV-2009 10:34:39.46
Attr MethodName = "Modbus_TCP_Server-IoRackWrite"
EndBody
EndObject
EndObject
Object Template Modbus_TCP_Server 2149285888 01-JAN-1970 01:00:00.00
Body RtBody 01-JAN-1970 01:00:00.00
EndBody
EndObject
EndObject
!/**
! @Version 1.0
! @Group IO
! @Summary Server Modue 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
! and is the father of channel objects that define the input and
! output area for the module.
!
! @classlink Modbus_TCP_Server otherio_modbus_tcp_server.html
!*/
Object Modbus_TCP_ServerModule $ClassDef 7 25-NOV-2009 11:05:45.82
Body SysBody 25-NOV-2009 11:05:23.49
Attr Editor = 0
Attr Method = 0
Attr Flags = 16464
EndBody
Object RtBody $ObjBodyDef 1 25-NOV-2009 11:05:23.49
Body SysBody 25-NOV-2009 11:06:00.66
Attr StructName = "Modbus_TCP_ServerModule"
Attr NextAix = "_X21"
EndBody
!/**
! Description of the object.
!*/
Object Description $Attribute 11 25-NOV-2009 11:05:23.49
Body SysBody 25-NOV-2009 11:05:23.49
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 12 04-DEC-2009 16:53:13.17
Body SysBody 04-DEC-2009 16:53:32.47
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 13 04-DEC-2009 16:53:43.87
Body SysBody 04-DEC-2009 16:53:45.81
Attr PgmName = "WriteAddress"
Attr TypeRef = "pwrs:Type-$UInt32"
EndBody
EndObject
!/**
! @Summary Unit id.
! Identification of the modbus unit to communicate with. 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).
!*/
Object UnitId $Attribute 14 25-NOV-2009 11:05:23.49
Body SysBody 25-NOV-2009 11:05:23.49
Attr PgmName = "UnitId"
Attr TypeRef = "pwrs:Type-$UInt16"
EndBody
EndObject
!/**
! Module status.
!*/
Object Status $Attribute 15 25-NOV-2009 11:05:23.49
Body SysBody 04-DEC-2009 17:13:22.55
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 18 25-NOV-2009 11:05:23.49
Body SysBody 25-NOV-2009 11:05:23.49
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 19 25-NOV-2009 11:05:23.49
Body SysBody 25-NOV-2009 11:05:23.49
Attr PgmName = "ThreadObject"
Attr TypeRef = "pwrs:Type-$Objid"
EndBody
EndObject
EndObject
Object IoMethods $RtMethod 66 25-NOV-2009 11:05:23.49
Object IoCardInit $Method 67 25-NOV-2009 11:05:23.49
Body SysBody 25-NOV-2009 11:14:04.41
Attr MethodName = "Modbus_TCP_ServerModule-IoCardInit"
EndBody
EndObject
Object IoCardRead $Method 68 25-NOV-2009 11:05:23.49
Body SysBody 25-NOV-2009 11:14:15.11
Attr MethodName = "Modbus_TCP_ServerModule-IoCardRead"
EndBody
EndObject
Object IoCardWrite $Method 69 25-NOV-2009 11:05:23.49
Body SysBody 25-NOV-2009 11:14:21.27
Attr MethodName = "Modbus_TCP_ServerModule-IoCardWrite"
EndBody
EndObject
EndObject
Object Template Modbus_TCP_ServerModule 2149548032 01-JAN-1970 01:00:00.00
Body RtBody 01-JAN-1970 01:00:00.00
EndBody
EndObject
EndObject
EndObject
EndVolume
......@@ -170,6 +170,7 @@ int main (
/* Once threads has set their priority don't run as root */
#if 0
ruid = getuid();
if (ruid == 0) {
......@@ -180,6 +181,7 @@ int main (
}
else
setreuid(ruid, ruid);
#endif
qcom_SignalOr(&sts, &qcom_cQini, ini_mEvent_newPlcInitDone);
qcom_WaitAnd(&sts, &pp->eventQ, &qcom_cQini, ini_mEvent_newPlcStart, qcom_cTmoEternal);
......
......@@ -29,6 +29,8 @@
#if defined(OS_LINUX)
# include <pwd.h>
# include <signal.h>
# include <linux/capability.h>
# include <sys/types.h>
#endif
#include "pwr.h"
......@@ -98,23 +100,6 @@ plc_thread (
phase = (long int)que_Get(&sts, &tp->q_in, NULL, NULL);
pwr_Assert(phase == 2);
/* Once thread's has set it's priority don't run as root */
#if defined(OS_LINUX)
struct passwd *pwd;
ruid = getuid();
if (ruid == 0) {
pwd = getpwnam("pwrp");
if (pwd != NULL) {
setreuid(pwd->pw_uid, pwd->pw_uid);
}
}
else
setreuid(ruid, ruid);
#endif
/* Phase 2. */
tp->init(2, tp);
......@@ -133,6 +118,24 @@ plc_thread (
errh_SetStatus( PLC__ERRINITIO);
}
/* Once thread's has set it's priority don't run as root */
#if defined(OS_LINUX)
struct passwd *pwd;
ruid = getuid();
if (ruid == 0) {
pwd = getpwnam("pwrp");
if (pwd != NULL) {
setreuid(pwd->pw_uid, pwd->pw_uid);
}
}
else
setreuid(ruid, ruid);
#endif
tp->init(0, tp);
if (tp->pp->IOHandler->IOReadWriteFlag) {
......
......@@ -273,6 +273,11 @@ SObject pwrb:Class
Attr SigValueUnit = "V"
EndBody
EndObject
Object PostCreate $DbCallBack
Body SysBody
Attr MethodName = "ChanIi-PostCreate"
EndBody
EndObject
Object Defaults $Object
Body SysBody
Attr Name = "%02.2d"
......
......@@ -261,6 +261,11 @@ SObject pwrb:Class
Attr Name = "%02.2d"
EndBody
EndObject
Object PostCreate $DbCallBack
Body SysBody
Attr MethodName = "ChanIi-PostCreate"
EndBody
EndObject
Object ConfiguratorPcsnn $Menu
Object Pointed $Menu
Object SetDefaults $MenuButton
......
......@@ -165,6 +165,11 @@ SObject pwrb:Class
Attr Name = "%02.2d"
EndBody
EndObject
Object PostCreate $DbCallBack
Body SysBody
Attr MethodName = "ChanDi-PostCreate"
EndBody
EndObject
Object ConfiguratorPcsnn $Menu
Object Pointed $Menu
Object SetDefaults $MenuButton
......
......@@ -197,6 +197,11 @@ SObject pwrb:Class
Attr Name = "%02.2d"
EndBody
EndObject
Object PostCreate $DbCallBack
Body SysBody
Attr MethodName = "ChanDi-PostCreate"
EndBody
EndObject
Object ConfiguratorPcsnn $Menu
Object Pointed $Menu
Object SetDefaults $MenuButton
......
......@@ -109,6 +109,11 @@ SObject pwrb:Class
Attr Representation = 0
EndBody
EndObject
Object PostCreate $DbCallBack
Body SysBody
Attr MethodName = "ChanIi-PostCreate"
EndBody
EndObject
Object RtXtt $RtMenu
Object Signal $MenuRef
Body SysBody
......
......@@ -138,6 +138,11 @@ SObject pwrb:Class
EndBody
EndObject
EndObject
Object PostCreate $DbCallBack
Body SysBody
Attr MethodName = "ChanIi-PostCreate"
EndBody
EndObject
Object RtXtt $RtMenu
Object Signal $MenuRef
Body SysBody
......
......@@ -27,8 +27,8 @@
#include "pwr_baseclasses.h"
#include "wb_ldh.h"
#include "wb_wsx.h"
#include "wb_session.h"
/*----------------------------------------------------------------------------*\
Syntax check.
\*----------------------------------------------------------------------------*/
......@@ -46,6 +46,104 @@ static pwr_tStatus SyntaxCheck (
return PWRB__SUCCESS;
}
static pwr_tStatus PostCreate( ldh_tSesContext Session,
pwr_tObjid Object,
pwr_tObjid Father,
pwr_tClassId Class)
{
wb_session *sp = (wb_session *)Session;
int repr_set = 0;
// Fetch Representation from previous sibling
wb_object o = sp->object( Object);
if ( !o) return o.sts();
wb_object before = o.before();
if ( before && before.cid() == o.cid()) {
// Set Representation
wb_attribute ba_repr = sp->attribute( before.oid(), "RtBody", "Representation");
if ( !ba_repr) return ba_repr.sts();
pwr_eDataRepEnum repr;
ba_repr.value( &repr);
wb_attribute a_repr = sp->attribute( Object, "RtBody", "Representation");
if ( !a_repr) return a_repr.sts();
try {
sp->writeAttribute( a_repr, &repr, sizeof(repr));
}
catch ( wb_error& e) {
return e.sts();
}
if ( sp->evenSts()) return sp->sts();
repr_set = 1;
// Set Number
wb_attribute ba_num = sp->attribute( before.oid(), "RtBody", "Number");
if ( !ba_num) return ba_num.sts();
pwr_tUInt16 num;
ba_num.value( &num);
num++;
pwr_tUInt16 max_num;
switch ( repr) {
case pwr_eDataRepEnum_Bit8:
max_num = 7;
break;
case pwr_eDataRepEnum_Bit16:
max_num = 15;
break;
case pwr_eDataRepEnum_Bit32:
max_num = 31;
break;
case pwr_eDataRepEnum_Bit64:
max_num = 63;
break;
default:
max_num = 31;
}
if ( num > max_num)
num = 0;
wb_attribute a_num = sp->attribute( Object, "RtBody", "Number");
if ( !a_num) return a_num.sts();
try {
sp->writeAttribute( a_num, &num, sizeof(num));
}
catch ( wb_error& e) {
return e.sts();
}
if ( sp->evenSts()) return sp->sts();
}
if ( !repr_set) {
wb_cdef father_cdef = sp->cdef(Class);
if ( strcmp( father_cdef.name(), "Modbus_TCP_ServerModule") == 0 ||
strcmp( father_cdef.name(), "Modbus_Module") == 0) {
wb_attribute a = sp->attribute( Object, "RtBody", "Representation");
if ( !a) return a.sts();
pwr_eDataRepEnum value = pwr_eDataRepEnum_Bit8;
try {
sp->writeAttribute( a, &value, sizeof(value));
}
catch ( wb_error& e) {
return e.sts();
}
if ( sp->evenSts()) return sp->sts();
}
}
return PWRB__SUCCESS;
}
/*----------------------------------------------------------------------------*\
Every method to be exported to the workbench should be registred here.
......@@ -53,5 +151,6 @@ static pwr_tStatus SyntaxCheck (
pwr_dExport pwr_BindMethods(ChanDi) = {
pwr_BindMethod(SyntaxCheck),
pwr_BindMethod(PostCreate),
pwr_NullMethod
};
......@@ -27,6 +27,7 @@
#include "pwr_baseclasses.h"
#include "wb_ldh.h"
#include "wb_wsx.h"
#include "wb_session.h"
/*----------------------------------------------------------------------------*\
......@@ -46,6 +47,65 @@ static pwr_tStatus SyntaxCheck (
return PWRB__SUCCESS;
}
static pwr_tStatus PostCreate( ldh_tSesContext Session,
pwr_tObjid Object,
pwr_tObjid Father,
pwr_tClassId Class)
{
wb_session *sp = (wb_session *)Session;
int repr_set = 0;
// Fetch Representation from previous sibling
wb_object o = sp->object( Object);
if ( !o) return o.sts();
wb_object before = o.before();
if ( before && before.cid() == o.cid()) {
// Set Representation
wb_attribute ba_repr = sp->attribute( before.oid(), "RtBody", "Representation");
if ( !ba_repr) return ba_repr.sts();
pwr_eDataRepEnum repr;
ba_repr.value( &repr);
wb_attribute a_repr = sp->attribute( Object, "RtBody", "Representation");
if ( !a_repr) return a_repr.sts();
try {
sp->writeAttribute( a_repr, &repr, sizeof(repr));
}
catch ( wb_error& e) {
return e.sts();
}
if ( sp->evenSts()) return sp->sts();
repr_set = 1;
}
if ( !repr_set) {
wb_cdef father_cdef = sp->cdef(Class);
if ( strcmp( father_cdef.name(), "Modbus_TCP_ServerModule") == 0 ||
strcmp( father_cdef.name(), "Modbus_Module") == 0) {
wb_attribute a = sp->attribute( Object, "RtBody", "Representation");
if ( !a) return a.sts();
pwr_eDataRepEnum value = pwr_eDataRepEnum_Int16;
try {
sp->writeAttribute( a, &value, sizeof(value));
}
catch ( wb_error& e) {
return e.sts();
}
if ( sp->evenSts()) return sp->sts();
}
}
return PWRB__SUCCESS;
}
/*----------------------------------------------------------------------------*\
Every method to be exported to the workbench should be registred here.
......@@ -53,5 +113,6 @@ static pwr_tStatus SyntaxCheck (
pwr_dExport pwr_BindMethods(ChanIi) = {
pwr_BindMethod(SyntaxCheck),
pwr_BindMethod(PostCreate),
pwr_NullMethod
};
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