1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-09 00:00:00 +01:00

Merge branch 'gtfpga'

This commit is contained in:
Steffen Vogel 2015-09-22 17:40:17 +02:00
commit df10c242af
17 changed files with 2323 additions and 2335 deletions

View file

@ -4,24 +4,6 @@ various simulators and tools to the S2SS server.
Author: Steffen Vogel <steffen.vogel@rwth-aachen.de>
Date: Mid 2014 - End 2015
- ml50x_cpld
A slightly modified configuration of the CPLD on the ML507 board.
It is based on the reference design provided by Xilinx.
The modification redirects the PCIe reset signal directly to the Virtex 5.
- ml507_gtfpga_pcie
A Xilinx ISE 12.4 project to directly access RTDS registers via PCIe memory.
This is a WIP and should allow improve the latency of by directly accessing RTDS
registers through the S2SS server which runs on the same machine.
- ml507_ppc440_udp
A Xilinx XPS 12.4 project which allows access to the RTDS registers via S2SS's
UDP protocol over the ML507 Ethernet interface.
This is working!
- opal
- opal/udp
Contains the implementation of an asynchronous process block for RT-LAB.
This block allows exchanging messages with an S2SS server over UDP/TCP.
- rscad
Some example RSCAD drafts to test the S2SS <-> RTDS interface.

View file

@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>s2ss_tests</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
</buildSpec>
<natures>
<nature>com.opalrt.rtlab.ui.rtlabnature</nature>
</natures>
</projectDescription>
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>s2ss_tests</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
</buildSpec>
<natures>
<nature>com.opalrt.rtlab.ui.rtlabnature</nature>
</natures>
</projectDescription>

View file

@ -1,3 +1,3 @@
#Mon Jul 14 20:43:18 CEST 2014
eclipse.preferences.version=1
rtprojectfile=s2ss_tests.llp
#Mon Jul 14 20:43:18 CEST 2014
eclipse.preferences.version=1
rtprojectfile=s2ss_tests.llp

View file

@ -0,0 +1,16 @@
/** Compiled-in settings
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2014, Institute for Automation of Complex Power Systems, EONERC
* @file
*/
#ifndef _CONFIG_H_
#define _CONFIG_H_
#define PROGNAME "S2SS"
#define VERSION "0.1"
#define MAX_VALUES 64
#endif /* _CONFIG_H_ */

View file

@ -1,35 +1,33 @@
/** Helper functions for socket
*
* Code example of an asynchronous program. This program is started
* by the asynchronous controller and demonstrates how to send and
* receive data to and from the asynchronous icons and a UDP or TCP
* port.
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @author Mathieu Dubé-Dallaire
* @copyright 2003, OPAL-RT Technologies inc
* @copyright 2014-2015, Institute for Automation of Complex Power Systems, EONERC
* This file is part of S2SS. All Rights Reserved. Proprietary and confidential.
* Unauthorized copying of this file, via any medium is strictly prohibited.
*********************************************************************************/
#ifndef _SOCKET_H_
#define _SOCKET_H_
#define RT
#include "OpalGenAsyncParamCtrl.h"
#define UDP_PROTOCOL 1
#define TCP_PROTOCOL 2
#define EOK 0
int InitSocket(Opal_GenAsyncParam_Ctrl IconCtrlStruct);
int SendPacket(char* DataSend, int datalength);
int RecvPacket(char* DataRecv, int datalength, double timeout);
int CloseSocket(Opal_GenAsyncParam_Ctrl IconCtrlStruct);
#endif /* _SOCKET_H_ */
/** Helper functions for socket
*
* Code example of an asynchronous program. This program is started
* by the asynchronous controller and demonstrates how to send and
* receive data to and from the asynchronous icons and a UDP or TCP
* port.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @author Mathieu Dubé-Dallaire
* @copyright 2014, Institute for Automation of Complex Power Systems, EONERC
* @copyright 2003, OPAL-RT Technologies inc
* @file
*/
#ifndef _SOCKET_H_
#define _SOCKET_H_
#define RT
#include "OpalGenAsyncParamCtrl.h"
#define UDP_PROTOCOL 1
#define TCP_PROTOCOL 2
#define EOK 0
int InitSocket(Opal_GenAsyncParam_Ctrl IconCtrlStruct);
int SendPacket(char* DataSend, int datalength);
int RecvPacket(char* DataRecv, int datalength, double timeout);
int CloseSocket(Opal_GenAsyncParam_Ctrl IconCtrlStruct);
#endif /* _SOCKET_H_ */

View file

@ -1,75 +1,75 @@
# Specify program name
PROGRAM = AsyncIP
# Specify default values if we are not compiling from RT-LAB
TARGET_OPALRT_ROOT = /usr/opalrt
# QNX v6.x
ifeq "$(SYSNAME)" "nto"
CC = gcc
LD = $(CC)
TARGET_LIB = -lsocket
endif
# RedHawk Linux
ifeq "$(shell uname)" "Linux"
RTLAB_INTEL_COMPILER ?= 1
# Intel Compiler support
ifeq ($(RTLAB_INTEL_COMPILER),1)
CC = opicc
LD = opicpc
# Gnu Compiler support
else
CC = gcc
LD = g++
INTEL_LIBS = -limf -lirc
endif
# RedHat or RedHawk
LINUX_FLAVOR = $(shell uname -r | grep RedHawk)
ifneq "$(LINUX_FLAVOR) " " " ### Linux (RedHat)
RH_FLAGS = -D_GNU_SOURCE -D__redhawk__
RH_LIBS = -lccur_rt
else
RH_FLAGS = -D_GNU_SOURCE
endif
TARGET_LIB = -lpthread -lm -ldl -lutil -lrt $(RH_LIBS) $(INTEL_LIBS)
endif
# Support for debugging symbols
ifeq ($(DEBUG),1)
CC_DEBUG_OPTS=-g -D_DEBUG
LD_DEBUG_OPTS=-g
else
CC_DEBUG_OPTS=-O
LD_DEBUG_OPTS=
endif
INCLUDES = -I.
LIBPATH = -L.
CC_OPTS =
LD_OPTS =
OBJS = s2ss.o msg.o utils.o socket.o
ADDLIB = -lOpalCore -lOpalUtils
LIBS = -lOpalAsyncApiCore $(ADDLIB) $(TARGET_LIB)
CFLAGS = -c $(CC_OPTS) $(CC_DEBUG_OPTS) $(RH_FLAGS) $(INCLUDES)
LDFLAGS = $(LD_OPTS) $(LD_DEBUG_OPTS) $(LIBPATH)
all: $(PROGRAM)
install:
\mkdir -p $(TARGET_OPALRT_ROOT)/local
\chmod 755 $(TARGET_OPALRT_ROOT)/local
\cp -f $(PROGRAM) $(TARGET_OPALRT_ROOT)/local
clean:
\rm -f $(OBJS) $(PROGRAM)
$(PROGRAM): $(OBJS)
$(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
chmod 777 $@
@echo "### Created executable: $(PROGRAM)"
# Specify program name
PROGRAM = AsyncIP
# Specify default values if we are not compiling from RT-LAB
TARGET_OPALRT_ROOT = /usr/opalrt
# QNX v6.x
ifeq "$(SYSNAME)" "nto"
CC = gcc
LD = $(CC)
TARGET_LIB = -lsocket
endif
# RedHawk Linux
ifeq "$(shell uname)" "Linux"
RTLAB_INTEL_COMPILER ?= 1
# Intel Compiler support
ifeq ($(RTLAB_INTEL_COMPILER),1)
CC = opicc
LD = opicpc
# Gnu Compiler support
else
CC = gcc
LD = g++
INTEL_LIBS = -limf -lirc
endif
# RedHat or RedHawk
LINUX_FLAVOR = $(shell uname -r | grep RedHawk)
ifneq "$(LINUX_FLAVOR) " " " ### Linux (RedHat)
RH_FLAGS = -D_GNU_SOURCE -D__redhawk__
RH_LIBS = -lccur_rt
else
RH_FLAGS = -D_GNU_SOURCE
endif
TARGET_LIB = -lpthread -lm -ldl -lutil -lrt $(RH_LIBS) $(INTEL_LIBS)
endif
# Support for debugging symbols
ifeq ($(DEBUG),1)
CC_DEBUG_OPTS=-g -D_DEBUG
LD_DEBUG_OPTS=-g
else
CC_DEBUG_OPTS=-O
LD_DEBUG_OPTS=
endif
INCLUDES = -I.
LIBPATH = -L.
CC_OPTS =
LD_OPTS =
OBJS = s2ss.o msg.o utils.o socket.o
ADDLIB = -lOpalCore -lOpalUtils
LIBS = -lOpalAsyncApiCore $(ADDLIB) $(TARGET_LIB)
CFLAGS = -c $(CC_OPTS) $(CC_DEBUG_OPTS) $(RH_FLAGS) $(INCLUDES)
LDFLAGS = $(LD_OPTS) $(LD_DEBUG_OPTS) $(LIBPATH)
all: $(PROGRAM)
install:
\mkdir -p $(TARGET_OPALRT_ROOT)/local
\chmod 755 $(TARGET_OPALRT_ROOT)/local
\cp -f $(PROGRAM) $(TARGET_OPALRT_ROOT)/local
clean:
\rm -f $(OBJS) $(PROGRAM)
$(PROGRAM): $(OBJS)
$(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
chmod 777 $@
@echo "### Created executable: $(PROGRAM)"

View file

@ -1,107 +1,107 @@
[EnvVars]
ABORT_COMPILE_WHEN_NO_BITSTREAM=0
ACTION_AFTER_N_OVERRUNS=10
ACTION_ON_OVERRUNS=0
AcquisitionMemory=0,2500,24,100
ActiveGroups=7/0/24/25/26/27/28/29/
CACHEABLE_DMA_MEMORY_ACCESS=ON
COMM_RT=UDP/IP
ClockPeriodMode=Free-Clock
ClockPeriodTime=10
DEBUG=0
DETECT_OVERRUNS=ON
ENABLE_WATCHDOG=ON
EXT_CC_OPTS=
EXT_LD_OPTS=
EXT_LIB=
EXT_LIBPATH=
MODEL_PAUSE_TIME=0.000000
MODEL_STOP_TIME=0.000000
MONITORING=ON
MONITORING_BLOCK=OFF
MONITORING_DISPLAY=NEVER
MSG_PRECISION_FACTOR=0
MaxDynamicSignals=2/0/100/24/42/
NB_STEP_WITHOUT_OVERRUNS=10
OPAL_DEBUG=OFF
OP_MATLABR2011B=1
OS_COMPILE_RELEASE=2.6.29.6-opalrt-5
PRINT_LOG_LEVEL=ALWAYS
RESET_IO_MISSING=ON
SYSNAME=linux
USER_INCS=
USER_SRCS=
WATCHDOG_TIMEOUT=5000
[EnvVars_REDHAWK_DYN_1]
INTERNAL_IGN_SOURCE_FILE=sfun_gen_async_ctrl.c sfun_recv_async.c sfun_send_async.c
INTERNAL_LIBRARY2=-lOpalAsyncApiR2011b
INTERNAL_LIBRARY3=-lOpalAsyncApiCore
[ExtraPutFilesComp]
include\config.h=Ascii
include\msg.h=Ascii
include\msg_format.h=Ascii
include\socket.h=Ascii
include\utils.h=Ascii
s2ss.mk=Ascii
src\msg.c=Ascii
src\s2ss.c=Ascii
src\socket.c=Ascii
src\utils.c=Ascii
[ExtraPutFilesComp_1_RT_LAB]
C:\OPAL-RT\RT-LAB\v10.5.9.356\common\lib\redhawk\libOpalAsyncApiCore.a=Binary
[General]
ATT_CHECKSUM1=703418586
ATT_CHECKSUM2=799511679
ATT_CHECKSUM3=2136361860
ATT_CHECKSUM4=3725771660
ATT_CREATED_BY=jwu
ATT_CREATED_ON=Thu Apr 15 08:21:54 1999
ATT_ENABLE_PTA=OFF
ATT_HANDLE_CONSOLE=ON
ATT_LAST_SAVED_BY=ACS
ATT_LAST_SAVED_ON=Thu Sep 04 16:25:19 2014
ATT_REVISION=1.445
AutoRetrieveFiles=ON
AutoRetrieveRtlab=ON
CompilerVersion=AUTOMATIC
DESCRIPTION=
DinamoFlag=OFF
FILENAME=D:\msv\02_msv-svo\opal\s2ss_tests\models\send_receive\send_receive.mdl
FORCE_RECOMPILE=0
IMPORTED_GLOBAL_VARIABLES=1
LastCompileRtlabVersion=v10.5.9.356
LastMatlabUsed=21
LastMatlabUsedName=v7.13
MATLAB_USED_IN_MODEL=21
Name=send_receive
PRINT_CYCLE=OFF
PostBuildCmd=
PreBuildCmd=
QNX_LAST_COMPILE_VERSION=
RH64_LAST_COMPILE_VERSION=
RH_LAST_COMPILE_VERSION=2.6.29.6-opalrt-5
ReportFileId=
RetrieveBuildTree=ON
RetrieveRootDir=
SimulationMode=2
TLC=Automatic
TMF=Automatic
TRANSFERFILE_AT_LOAD=OFF
TargetCompileCmd=/usr/bin/make -f /usr/opalrt/common/bin/opalmodelmk
TargetPlatform=REDHAWK
TimeFactor=1.000000000000000
TimeStep=0.000050000000000
sc_consoleTimeStep=-1.000000000000000
sm_modelTimeStep=0.000049999998737
sm_send_receiveTimeStep=0.000049999998737
[NodeMapping]
sm_model=ACS_OPAL_RT
sm_model_CORE_ASSIGNATION=1
sm_model_CPU=-1
sm_model_DEBUG=OFF
sm_model_XHP_ENABLE=FALSE
sm_send_receive=ACS_OPAL_RT
sm_send_receive_CORE_ASSIGNATION=1
sm_send_receive_CPU=-1
sm_send_receive_DEBUG=OFF
sm_send_receive_XHP_ENABLE=FALSE
[EnvVars]
ABORT_COMPILE_WHEN_NO_BITSTREAM=0
ACTION_AFTER_N_OVERRUNS=10
ACTION_ON_OVERRUNS=0
AcquisitionMemory=0,2500,24,100
ActiveGroups=7/0/24/25/26/27/28/29/
CACHEABLE_DMA_MEMORY_ACCESS=ON
COMM_RT=UDP/IP
ClockPeriodMode=Free-Clock
ClockPeriodTime=10
DEBUG=0
DETECT_OVERRUNS=ON
ENABLE_WATCHDOG=ON
EXT_CC_OPTS=
EXT_LD_OPTS=
EXT_LIB=
EXT_LIBPATH=
MODEL_PAUSE_TIME=0.000000
MODEL_STOP_TIME=0.000000
MONITORING=ON
MONITORING_BLOCK=OFF
MONITORING_DISPLAY=NEVER
MSG_PRECISION_FACTOR=0
MaxDynamicSignals=2/0/100/24/42/
NB_STEP_WITHOUT_OVERRUNS=10
OPAL_DEBUG=OFF
OP_MATLABR2011B=1
OS_COMPILE_RELEASE=2.6.29.6-opalrt-5
PRINT_LOG_LEVEL=ALWAYS
RESET_IO_MISSING=ON
SYSNAME=linux
USER_INCS=
USER_SRCS=
WATCHDOG_TIMEOUT=5000
[EnvVars_REDHAWK_DYN_1]
INTERNAL_IGN_SOURCE_FILE=sfun_gen_async_ctrl.c sfun_recv_async.c sfun_send_async.c
INTERNAL_LIBRARY2=-lOpalAsyncApiR2011b
INTERNAL_LIBRARY3=-lOpalAsyncApiCore
[ExtraPutFilesComp]
include\config.h=Ascii
include\msg.h=Ascii
include\msg_format.h=Ascii
include\socket.h=Ascii
include\utils.h=Ascii
s2ss.mk=Ascii
src\msg.c=Ascii
src\s2ss.c=Ascii
src\socket.c=Ascii
src\utils.c=Ascii
[ExtraPutFilesComp_1_RT_LAB]
C:\OPAL-RT\RT-LAB\v10.5.9.356\common\lib\redhawk\libOpalAsyncApiCore.a=Binary
[General]
ATT_CHECKSUM1=703418586
ATT_CHECKSUM2=799511679
ATT_CHECKSUM3=2136361860
ATT_CHECKSUM4=3725771660
ATT_CREATED_BY=jwu
ATT_CREATED_ON=Thu Apr 15 08:21:54 1999
ATT_ENABLE_PTA=OFF
ATT_HANDLE_CONSOLE=ON
ATT_LAST_SAVED_BY=ACS
ATT_LAST_SAVED_ON=Thu Sep 04 16:25:19 2014
ATT_REVISION=1.445
AutoRetrieveFiles=ON
AutoRetrieveRtlab=ON
CompilerVersion=AUTOMATIC
DESCRIPTION=
DinamoFlag=OFF
FILENAME=D:\msv\02_msv-svo\opal\s2ss_tests\models\send_receive\send_receive.mdl
FORCE_RECOMPILE=0
IMPORTED_GLOBAL_VARIABLES=1
LastCompileRtlabVersion=v10.5.9.356
LastMatlabUsed=21
LastMatlabUsedName=v7.13
MATLAB_USED_IN_MODEL=21
Name=send_receive
PRINT_CYCLE=OFF
PostBuildCmd=
PreBuildCmd=
QNX_LAST_COMPILE_VERSION=
RH64_LAST_COMPILE_VERSION=
RH_LAST_COMPILE_VERSION=2.6.29.6-opalrt-5
ReportFileId=
RetrieveBuildTree=ON
RetrieveRootDir=
SimulationMode=2
TLC=Automatic
TMF=Automatic
TRANSFERFILE_AT_LOAD=OFF
TargetCompileCmd=/usr/bin/make -f /usr/opalrt/common/bin/opalmodelmk
TargetPlatform=REDHAWK
TimeFactor=1.000000000000000
TimeStep=0.000050000000000
sc_consoleTimeStep=-1.000000000000000
sm_modelTimeStep=0.000049999998737
sm_send_receiveTimeStep=0.000049999998737
[NodeMapping]
sm_model=ACS_OPAL_RT
sm_model_CORE_ASSIGNATION=1
sm_model_CPU=-1
sm_model_DEBUG=OFF
sm_model_XHP_ENABLE=FALSE
sm_send_receive=ACS_OPAL_RT
sm_send_receive_CORE_ASSIGNATION=1
sm_send_receive_CPU=-1
sm_send_receive_DEBUG=OFF
sm_send_receive_XHP_ENABLE=FALSE

View file

@ -1,350 +1,362 @@
/** Main
*
* Code example of an asynchronous program. This program is started
* by the asynchronous controller and demonstrates how to send and
* receive data to and from the asynchronous icons and a UDP or TCP
* port.
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @author Mathieu Dubé-Dallaire
* @copyright 2003, OPAL-RT Technologies inc
* @copyright 2014-2015, Institute for Automation of Complex Power Systems, EONERC
* This file is part of S2SS. All Rights Reserved. Proprietary and confidential.
* Unauthorized copying of this file, via any medium is strictly prohibited.
*********************************************************************************/
/* Standard ANSI C headers needed for this program */
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <termios.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#if defined(__QNXNTO__)
#include <process.h>
#include <pthread.h>
#include <devctl.h>
#include <sys/dcmd_chr.h>
#elif defined(__linux__)
#define _GNU_SOURCE 1
#endif
/* Define RTLAB before including OpalPrint.h for messages to be sent
* to the OpalDisplay. Otherwise stdout will be used. */
#define RTLAB
#include "OpalPrint.h"
#include "AsyncApi.h"
/* This is the message format */
#include "config.h"
#include "msg.h"
#include "socket.h"
/* This is just for initializing the shared memory access to communicate
* with the RT-LAB model. It's easier to remember the arguments like this */
#define ASYNC_SHMEM_NAME argv[1]
#define ASYNC_SHMEM_SIZE atoi(argv[2])
#define PRINT_SHMEM_NAME argv[3]
#ifdef _DEBUG // TODO: workaround
#define CPU_TICKS 3466948000
struct msg *msg_send = NULL;
void Tick(int sig, siginfo_t *si, void *ptr)
{
Opal_GenAsyncParam_Ctrl *IconCtrlStruct;
unsigned long long CpuTime, CpuTimeStart;
double ModelTime;
if (!msg_send)
return;
IconCtrlStruct = (Opal_GenAsyncParam_Ctrl*) si->si_value.sival_ptr;
OpalGetAsyncStartExecCpuTime(IconCtrlStruct, &CpuTimeStart);
OpalGetAsyncModelTime(IconCtrlStruct, &CpuTime, &ModelTime);
OpalPrint("%s: CpuTime: %llu\tModelTime: %.3f\tSequence: %hu\tValue: %.2f\n",
PROGNAME, (CpuTime - CpuTimeStart) / CPU_TICKS, ModelTime, ntohs(msg_send->sequence), msg_send->data[0].f);
}
#endif /* _DEBUG */
static void *SendToIPPort(void *arg)
{
unsigned int SendID = 1;
unsigned int ModelState;
unsigned int i, n;
unsigned short seq = 0;
int nbSend = 0;
/* Data from OPAL-RT model */
double mdldata[MSG_VALUES];
int mdldata_size;
/* Data from the S2SS server */
struct msg msg = MSG_INIT(0);
int len;
#ifdef _DEBUG // TODO: workaround
msg_send = &msg;
#endif /* _DEBUG */
OpalPrint("%s: SendToIPPort thread started\n", PROGNAME);
OpalGetNbAsyncSendIcon(&nbSend);
if (nbSend >= 1) {
do {
/* This call unblocks when the 'Data Ready' line of a send icon is asserted. */
if ((n = OpalWaitForAsyncSendRequest(&SendID)) != EOK) {
ModelState = OpalGetAsyncModelState();
if ((ModelState != STATE_RESET) && (ModelState != STATE_STOP)) {
OpalSetAsyncSendIconError(n, SendID);
OpalPrint("%s: OpalWaitForAsyncSendRequest(), errno %d\n", PROGNAME, n);
}
continue;
}
/* No errors encountered yet */
OpalSetAsyncSendIconError(0, SendID);
/* Get the size of the data being sent by the unblocking SendID */
OpalGetAsyncSendIconDataLength(&mdldata_size, SendID);
if (mdldata_size / sizeof(double) > MSG_VALUES) {
OpalPrint("%s: Number of signals for SendID=%d exceeds allowed maximum (%d)\n",
PROGNAME, SendID, MSG_VALUES);
return NULL;
}
/* Read data from the model */
OpalGetAsyncSendIconData(mdldata, mdldata_size, SendID);
msg.sequence = htons(seq++);
msg.length = mdldata_size / sizeof(double);
for (i = 0; i < msg.length; i++)
msg.data[i].f = (float) mdldata[i];
len = MSG_LEN(&msg);
/* Perform the actual write to the ip port */
if (SendPacket((char *) &msg, len) < 0)
OpalSetAsyncSendIconError(errno, SendID);
else
OpalSetAsyncSendIconError(0, SendID);
/* This next call allows the execution of the "asynchronous" process
* to actually be synchronous with the model. To achieve this, you
* should set the "Sending Mode" in the Async_Send block to
* NEED_REPLY_BEFORE_NEXT_SEND or NEED_REPLY_NOW. This will force
* the model to wait for this process to call this
* OpalAsyncSendRequestDone function before continuing. */
OpalAsyncSendRequestDone(SendID);
/* Before continuing, we make sure that the real-time model
* has not been stopped. If it has, we quit. */
ModelState = OpalGetAsyncModelState();
} while ((ModelState != STATE_RESET) && (ModelState != STATE_STOP));
OpalPrint("%s: SendToIPPort: Finished\n", PROGNAME);
}
else {
OpalPrint("%s: SendToIPPort: No transimission block for this controller. Stopping thread.\n", PROGNAME);
}
return NULL;
}
static void *RecvFromIPPort(void *arg)
{
unsigned RecvID = 1;
unsigned i, n;
int nbRecv = 0;
unsigned ModelState;
/* Data from OPAL-RT model */
double mdldata[MSG_VALUES];
int mdldata_size;
/* Data from the S2SS server */
struct msg msg = MSG_INIT(0);
int len;
OpalPrint("%s: RecvFromIPPort thread started\n", PROGNAME);
OpalGetNbAsyncRecvIcon(&nbRecv);
if (nbRecv >= 1) {
do {
n = RecvPacket((char *) &msg, sizeof(msg), 1.0);
int ret = msg_verify(m);
if (ret) {
printf("Dropping invalid message (reason=%d)\r\n", ret);
goto out;
}
/** @todo: We may check the sequence number here. */
msg.sequence = ntohs(msg.sequence);
if (msg.endian != MSG_ENDIAN_HOST)
msg_swap(&msg);
len = MSG_LEN(&msg);
if (n < 1) {
ModelState = OpalGetAsyncModelState();
if ((ModelState != STATE_RESET) && (ModelState != STATE_STOP)) {
// n == 0 means timeout, so we continue silently
//if (n == 0)
// OpalPrint("%s: Timeout while waiting for data\n", PROGNAME, errno);
// n == -1 means a more serious error, so we print it
if (n == -1)
OpalPrint("%s: Error %d while waiting for data\n", PROGNAME, errno);
continue;
}
break;
}
else if (n != len) {
OpalPrint("%s: Received incoherent packet (size: %d, complete: %d)\n", PROGNAME, n, len);
continue;
}
OpalSetAsyncRecvIconStatus(msg.sequence, RecvID); /* Set the Status to the message ID */
OpalSetAsyncRecvIconError(0, RecvID); /* Set the Error to 0 */
/* Get the number of signals to send back to the model */
OpalGetAsyncRecvIconDataLength(&mdldata_size, RecvID);
if (mdldata_size / sizeof(double) > MSG_VALUES) {
OpalPrint("%s: Number of signals for RecvID=%d (%d) exceeds allowed maximum (%d)\n",
PROGNAME, RecvID, mdldata_size / sizeof(double), MSG_VALUES);
return NULL;
}
if (mdldata_size / sizeof(double) > msg.length) {
OpalPrint("%s: Number of signals for RecvID=%d (%d) exceeds what was received (%d)\n",
PROGNAME, RecvID, mdldata_size / sizeof(double), msg.length);
}
for (i = 0; i < msg.length; i++)
mdldata[i] = (double) msg.data[i].f;
OpalSetAsyncRecvIconData(mdldata, mdldata_size, RecvID);
/* Before continuing, we make sure that the real-time model
* has not been stopped. If it has, we quit. */
ModelState = OpalGetAsyncModelState();
} while ((ModelState != STATE_RESET) && (ModelState != STATE_STOP));
OpalPrint("%s: RecvFromIPPort: Finished\n", PROGNAME);
}
else {
OpalPrint("%s: RecvFromIPPort: No reception block for this controller. Stopping thread.\n", PROGNAME);
}
return NULL;
}
int main(int argc, char *argv[])
{
int err;
Opal_GenAsyncParam_Ctrl IconCtrlStruct;
pthread_t tid_send, tid_recv;
pthread_attr_t attr_send, attr_recv;
OpalPrint("%s: This is a S2SS client\n", PROGNAME);
/* Check for the proper arguments to the program */
if (argc < 4) {
printf("Invalid Arguments: 1-AsyncShmemName 2-AsyncShmemSize 3-PrintShmemName\n");
exit(0);
}
/* Enable the OpalPrint function. This prints to the OpalDisplay. */
if (OpalSystemCtrl_Register(PRINT_SHMEM_NAME) != EOK) {
printf("%s: ERROR: OpalPrint() access not available\n", PROGNAME);
exit(EXIT_FAILURE);
}
/* Open Share Memory created by the model. */
if ((OpalOpenAsyncMem(ASYNC_SHMEM_SIZE, ASYNC_SHMEM_NAME)) != EOK) {
OpalPrint("%s: ERROR: Model shared memory not available\n", PROGNAME);
exit(EXIT_FAILURE);
}
/* For Redhawk, Assign this process to CPU 0 in order to support partial XHP */
AssignProcToCpu0();
/* Get IP Controler Parameters (ie: ip address, port number...) and
* initialize the device on the QNX node. */
memset(&IconCtrlStruct, 0, sizeof(IconCtrlStruct));
if ((err = OpalGetAsyncCtrlParameters(&IconCtrlStruct, sizeof(IconCtrlStruct))) != EOK) {
OpalPrint("%s: ERROR: Could not get controller parameters (%d).\n", PROGNAME, err);
exit(EXIT_FAILURE);
}
/* Initialize socket */
if (InitSocket(IconCtrlStruct) != EOK) {
OpalPrint("%s: ERROR: Initialization failed.\n", PROGNAME);
exit(EXIT_FAILURE);
}
#ifdef _DEBUG
/* Setup signals */
struct sigaction sa_tick = {
.sa_flags = SA_SIGINFO,
.sa_sigaction = Tick
};
sigemptyset(&sa_tick.sa_mask);
sigaction(SIGUSR1, &sa_tick, NULL);
/* Setup timer */
timer_t t;
struct sigevent sev = {
.sigev_notify = SIGEV_SIGNAL,
.sigev_signo = SIGUSR1,
.sigev_value.sival_ptr = &IconCtrlStruct
};
struct itimerspec its = {
.it_interval = { 1, 0 },
.it_value = { 0, 1 }
};
timer_create(CLOCK_REALTIME, &sev, &t);
timer_settime(t, 0, &its, NULL);
#endif /* _DEBUG */
/* Start send/receive threads */
if ((pthread_create(&tid_send, NULL, SendToIPPort, NULL)) == -1)
OpalPrint("%s: ERROR: Could not create thread (SendToIPPort), errno %d\n", PROGNAME, errno);
if ((pthread_create(&tid_recv, NULL, RecvFromIPPort, NULL)) == -1)
OpalPrint("%s: ERROR: Could not create thread (RecvFromIPPort), errno %d\n", PROGNAME, errno);
/* Wait for both threads to finish */
if ((err = pthread_join(tid_send, NULL)) != 0)
OpalPrint("%s: ERROR: pthread_join (SendToIPPort), errno %d\n", PROGNAME, err);
if ((err = pthread_join(tid_recv, NULL)) != 0)
OpalPrint("%s: ERROR: pthread_join (RecvFromIPPort), errno %d\n", PROGNAME, err);
/* Close the ip port and shared memories */
CloseSocket(IconCtrlStruct);
OpalCloseAsyncMem (ASYNC_SHMEM_SIZE, ASYNC_SHMEM_NAME);
OpalSystemCtrl_UnRegister(PRINT_SHMEM_NAME);
#ifdef _DEBUG
timer_delete(t);
#endif /* _DEBUG */
return 0;
}
/** Main
*
* Code example of an asynchronous program. This program is started
* by the asynchronous controller and demonstrates how to send and
* receive data to and from the asynchronous icons and a UDP or TCP
* port.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @author Mathieu Dubé-Dallaire
* @copyright 2014, Institute for Automation of Complex Power Systems, EONERC
* @copyright 2003, OPAL-RT Technologies inc
* @file
*/
/* Standard ANSI C headers needed for this program */
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <termios.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#if defined(__QNXNTO__)
# include <process.h>
# include <pthread.h>
# include <devctl.h>
# include <sys/dcmd_chr.h>
#elif defined(__linux__)
# define _GNU_SOURCE 1
#endif
/* Define RTLAB before including OpalPrint.h for messages to be sent
* to the OpalDisplay. Otherwise stdout will be used. */
#define RTLAB
#include "OpalPrint.h"
#include "AsyncApi.h"
/* This is the message format */
#include "config.h"
#include "msg.h"
#include "socket.h"
/* This is just for initializing the shared memory access to communicate
* with the RT-LAB model. It's easier to remember the arguments like this */
#define ASYNC_SHMEM_NAME argv[1]
#define ASYNC_SHMEM_SIZE atoi(argv[2])
#define PRINT_SHMEM_NAME argv[3]
#ifdef _DEBUG // TODO: workaround
#define CPU_TICKS 3466948000
struct msg *msg_send = NULL;
void Tick(int sig, siginfo_t *si, void *ptr)
{
Opal_GenAsyncParam_Ctrl *IconCtrlStruct;
unsigned long long CpuTime, CpuTimeStart;
double ModelTime;
if (!msg_send)
return;
IconCtrlStruct = (Opal_GenAsyncParam_Ctrl*) si->si_value.sival_ptr;
OpalGetAsyncStartExecCpuTime(IconCtrlStruct, &CpuTimeStart);
OpalGetAsyncModelTime(IconCtrlStruct, &CpuTime, &ModelTime);
OpalPrint("%s: CpuTime: %llu\tModelTime: %.3f\tSequence: %hu\tValue: %.2f\n",
PROGNAME, (CpuTime - CpuTimeStart) / CPU_TICKS, ModelTime, ntohs(msg_send->sequence), msg_send->data[0].f);
}
#endif /* _DEBUG */
static void *SendToIPPort(void *arg)
{
unsigned int SendID = 1;
unsigned int ModelState;
unsigned int i, n;
unsigned short seq = 0;
int nbSend = 0;
/* Data from OPAL-RT model */
double mdldata[MSG_VALUES];
int mdldata_size;
/* Data from the S2SS server */
struct msg msg = MSG_INIT(0);
int msg_size;
#ifdef _DEBUG // TODO: workaround
msg_send = &msg;
#endif /* _DEBUG */
OpalPrint("%s: SendToIPPort thread started\n", PROGNAME);
OpalGetNbAsyncSendIcon(&nbSend);
if (nbSend >= 1) {
do {
/* This call unblocks when the 'Data Ready' line of a send icon is asserted. */
if ((n = OpalWaitForAsyncSendRequest(&SendID)) != EOK) {
ModelState = OpalGetAsyncModelState();
if ((ModelState != STATE_RESET) && (ModelState != STATE_STOP)) {
OpalSetAsyncSendIconError(n, SendID);
OpalPrint("%s: OpalWaitForAsyncSendRequest(), errno %d\n", PROGNAME, n);
}
continue;
}
/* No errors encountered yet */
OpalSetAsyncSendIconError(0, SendID);
/* Get the size of the data being sent by the unblocking SendID */
OpalGetAsyncSendIconDataLength(&mdldata_size, SendID);
if (mdldata_size / sizeof(double) > MSG_VALUES) {
OpalPrint("%s: Number of signals for SendID=%d exceeds allowed maximum (%d)\n",
PROGNAME, SendID, MSG_VALUES);
return NULL;
}
/* Read data from the model */
OpalGetAsyncSendIconData(mdldata, mdldata_size, SendID);
/******* FORMAT TO SPECIFIC PROTOCOL HERE *****************************/
// msg.dev_id = SendID; /* Use the SendID as a device ID here */
msg.sequence = htons(seq++);
msg.length = mdldata_size / sizeof(double);
for (i = 0; i < msg.length; i++)
msg.data[i].f = (float) mdldata[i];
msg_size = MSG_LEN(msg.length);
/**********************************************************************/
/* Perform the actual write to the ip port */
if (SendPacket((char *) &msg, msg_size) < 0)
OpalSetAsyncSendIconError(errno, SendID);
else
OpalSetAsyncSendIconError(0, SendID);
/* This next call allows the execution of the "asynchronous" process
* to actually be synchronous with the model. To achieve this, you
* should set the "Sending Mode" in the Async_Send block to
* NEED_REPLY_BEFORE_NEXT_SEND or NEED_REPLY_NOW. This will force
* the model to wait for this process to call this
* OpalAsyncSendRequestDone function before continuing. */
OpalAsyncSendRequestDone(SendID);
/* Before continuing, we make sure that the real-time model
* has not been stopped. If it has, we quit. */
ModelState = OpalGetAsyncModelState();
} while ((ModelState != STATE_RESET) && (ModelState != STATE_STOP));
OpalPrint("%s: SendToIPPort: Finished\n", PROGNAME);
}
else {
OpalPrint("%s: SendToIPPort: No transimission block for this controller. Stopping thread.\n", PROGNAME);
}
return NULL;
}
static void *RecvFromIPPort(void *arg)
{
unsigned RecvID = 1;
unsigned i, n;
int nbRecv = 0;
unsigned ModelState;
/* Data from OPAL-RT model */
double mdldata[MSG_VALUES];
int mdldata_size;
/* Data from the S2SS server */
struct msg msg = MSG_INIT(0);
unsigned msg_size;
OpalPrint("%s: RecvFromIPPort thread started\n", PROGNAME);
OpalGetNbAsyncRecvIcon(&nbRecv);
if (nbRecv >= 1) {
do {
/******* FORMAT TO SPECIFIC PROTOCOL HERE ******************************/
n = RecvPacket((char *) &msg, sizeof(msg), 1.0);
/** @todo: Check and ntohs() sequence number! */
if (msg.version != MSG_VERSION) {
OpalPrint("%s: Received message with unknown version. Skipping..\n", PROGNAME);
continue;
}
else if (msg.type != MSG_TYPE_DATA) {
OpalPrint("%s: Received no data. Skipping..\n", PROGNAME);
continue;
}
/** @todo: We may check the sequence number here. */
msg.sequence = ntohs(msg.sequence);
if (msg.endian != MSG_ENDIAN_HOST)
msg_swap(&msg);
msg_size = MSG_LEN(msg.length);
/***********************************************************************/
if (n < 1) {
ModelState = OpalGetAsyncModelState();
if ((ModelState != STATE_RESET) && (ModelState != STATE_STOP)) {
// n == 0 means timeout, so we continue silently
//if (n == 0)
// OpalPrint("%s: Timeout while waiting for data\n", PROGNAME, errno);
// n == -1 means a more serious error, so we print it
if (n == -1)
OpalPrint("%s: Error %d while waiting for data\n", PROGNAME, errno);
continue;
}
break;
}
else if (n != msg_size) {
OpalPrint("%s: Received incoherent packet (size: %d, complete: %d)\n", PROGNAME, n, msg_size);
continue;
}
/******* FORMAT TO SPECIFIC PROTOCOL HERE *******************************/
OpalSetAsyncRecvIconStatus(msg.sequence, RecvID); /* Set the Status to the message ID */
OpalSetAsyncRecvIconError(0, RecvID); /* Set the Error to 0 */
/* Get the number of signals to send back to the model */
OpalGetAsyncRecvIconDataLength(&mdldata_size, RecvID);
if (mdldata_size / sizeof(double) > MSG_VALUES) {
OpalPrint("%s: Number of signals for RecvID=%d (%d) exceeds allowed maximum (%d)\n",
PROGNAME, RecvID, mdldata_size / sizeof(double), MSG_VALUES);
return NULL;
}
if (mdldata_size / sizeof(double) > msg.length) {
OpalPrint("%s: Number of signals for RecvID=%d (%d) exceeds what was received (%d)\n",
PROGNAME, RecvID, mdldata_size / sizeof(double), msg.length);
}
for (i = 0; i < msg.length; i++)
mdldata[i] = (double) msg.data[i].f;
/************************************************************************/
OpalSetAsyncRecvIconData(mdldata, mdldata_size, RecvID);
/* Before continuing, we make sure that the real-time model
* has not been stopped. If it has, we quit. */
ModelState = OpalGetAsyncModelState();
} while ((ModelState != STATE_RESET) && (ModelState != STATE_STOP));
OpalPrint("%s: RecvFromIPPort: Finished\n", PROGNAME);
}
else {
OpalPrint("%s: RecvFromIPPort: No reception block for this controller. Stopping thread.\n", PROGNAME);
}
return NULL;
}
int main(int argc, char *argv[])
{
int err;
Opal_GenAsyncParam_Ctrl IconCtrlStruct;
pthread_t tid_send, tid_recv;
pthread_attr_t attr_send, attr_recv;
OpalPrint("%s: This is a S2SS client\n", PROGNAME);
/* Check for the proper arguments to the program */
if (argc < 4) {
printf("Invalid Arguments: 1-AsyncShmemName 2-AsyncShmemSize 3-PrintShmemName\n");
exit(0);
}
/* Enable the OpalPrint function. This prints to the OpalDisplay. */
if (OpalSystemCtrl_Register(PRINT_SHMEM_NAME) != EOK) {
printf("%s: ERROR: OpalPrint() access not available\n", PROGNAME);
exit(EXIT_FAILURE);
}
/* Open Share Memory created by the model. */
if ((OpalOpenAsyncMem(ASYNC_SHMEM_SIZE, ASYNC_SHMEM_NAME)) != EOK) {
OpalPrint("%s: ERROR: Model shared memory not available\n", PROGNAME);
exit(EXIT_FAILURE);
}
/* For Redhawk, Assign this process to CPU 0 in order to support partial XHP */
AssignProcToCpu0();
/* Get IP Controler Parameters (ie: ip address, port number...) and
* initialize the device on the QNX node. */
memset(&IconCtrlStruct, 0, sizeof(IconCtrlStruct));
if ((err = OpalGetAsyncCtrlParameters(&IconCtrlStruct, sizeof(IconCtrlStruct))) != EOK) {
OpalPrint("%s: ERROR: Could not get controller parameters (%d).\n", PROGNAME, err);
exit(EXIT_FAILURE);
}
/* Initialize socket */
if (InitSocket(IconCtrlStruct) != EOK) {
OpalPrint("%s: ERROR: Initialization failed.\n", PROGNAME);
exit(EXIT_FAILURE);
}
#ifdef _DEBUG
/* Setup signals */
struct sigaction sa_tick = {
.sa_flags = SA_SIGINFO,
.sa_sigaction = Tick
};
sigemptyset(&sa_tick.sa_mask);
sigaction(SIGUSR1, &sa_tick, NULL);
/* Setup timer */
timer_t t;
struct sigevent sev = {
.sigev_notify = SIGEV_SIGNAL,
.sigev_signo = SIGUSR1,
.sigev_value.sival_ptr = &IconCtrlStruct
};
struct itimerspec its = {
.it_interval = { 1, 0 },
.it_value = { 0, 1 }
};
timer_create(CLOCK_REALTIME, &sev, &t);
timer_settime(t, 0, &its, NULL);
#endif /* _DEBUG */
/* Start send/receive threads */
if ((pthread_create(&tid_send, NULL, SendToIPPort, NULL)) == -1)
OpalPrint("%s: ERROR: Could not create thread (SendToIPPort), errno %d\n", PROGNAME, errno);
if ((pthread_create(&tid_recv, NULL, RecvFromIPPort, NULL)) == -1)
OpalPrint("%s: ERROR: Could not create thread (RecvFromIPPort), errno %d\n", PROGNAME, errno);
/* Wait for both threads to finish */
if ((err = pthread_join(tid_send, NULL)) != 0)
OpalPrint("%s: ERROR: pthread_join (SendToIPPort), errno %d\n", PROGNAME, err);
if ((err = pthread_join(tid_recv, NULL)) != 0)
OpalPrint("%s: ERROR: pthread_join (RecvFromIPPort), errno %d\n", PROGNAME, err);
/* Close the ip port and shared memories */
CloseSocket(IconCtrlStruct);
OpalCloseAsyncMem (ASYNC_SHMEM_SIZE, ASYNC_SHMEM_NAME);
OpalSystemCtrl_UnRegister(PRINT_SHMEM_NAME);
#ifdef _DEBUG
timer_delete(t);
#endif /* _DEBUG */
return 0;
}

View file

@ -1,225 +1,223 @@
/** Helper functions for socket
*
* Code example of an asynchronous program. This program is started
* by the asynchronous controller and demonstrates how to send and
* receive data to and from the asynchronous icons and a UDP or TCP
* port.
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @author Mathieu Dubé-Dallaire
* @copyright 2003, OPAL-RT Technologies inc
* @copyright 2014-2015, Institute for Automation of Complex Power Systems, EONERC
* This file is part of S2SS. All Rights Reserved. Proprietary and confidential.
* Unauthorized copying of this file, via any medium is strictly prohibited.
*********************************************************************************/
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
/* Define RTLAB before including OpalPrint.h for messages to be sent
* to the OpalDisplay. Otherwise stdout will be used. */
#define RTLAB
#include "OpalPrint.h"
#include "AsyncApi.h"
#include "config.h"
#include "socket.h"
/* Globals variables */
struct sockaddr_in send_ad; /* Send address */
struct sockaddr_in recv_ad; /* Receive address */
int sd = -1; /* socket descriptor */
int proto = UDP_PROTOCOL;
int InitSocket(Opal_GenAsyncParam_Ctrl IconCtrlStruct)
{
struct ip_mreq mreq; /* Multicast group structure */
int socket_type;
int socket_proto;
unsigned char TTL = 1;
unsigned char LOOP = 0;
int rc;
proto = (int) IconCtrlStruct.FloatParam[0];
OpalPrint("%s: Version : %s\n", PROGNAME, VERSION);
switch (proto) {
case UDP_PROTOCOL: /* Communication using UDP/IP protocol */
socket_proto = IPPROTO_UDP;
socket_type = SOCK_DGRAM;
OpalPrint("%s: Protocol : UDP/IP\n", PROGNAME);
break;
case TCP_PROTOCOL: /* Communication using TCP/IP protocol */
socket_proto = IPPROTO_IP;
socket_type = SOCK_STREAM;
OpalPrint("%s: Protocol : TCP/IP\n", PROGNAME);
break;
default: /* Protocol is not recognized */
OpalPrint("%s: ERROR: Protocol (%d) not supported!\n", PROGNAME, proto);
return EINVAL;
}
OpalPrint("%s: Remote Address : %s\n", PROGNAME, IconCtrlStruct.StringParam[0]);
OpalPrint("%s: Remote Port : %d\n", PROGNAME, (int) IconCtrlStruct.FloatParam[1]);
/* Initialize the socket */
if ((sd = socket(AF_INET, socket_type, socket_proto)) < 0) {
OpalPrint("%s: ERROR: Could not open socket\n", PROGNAME);
return EIO;
}
/* Set the structure for the remote port and address */
memset(&send_ad, 0, sizeof(send_ad));
send_ad.sin_family = AF_INET;
send_ad.sin_addr.s_addr = inet_addr(IconCtrlStruct.StringParam[0]);
send_ad.sin_port = htons((u_short)IconCtrlStruct.FloatParam[1]);
/* Set the structure for the local port and address */
memset(&recv_ad, 0, sizeof(recv_ad));
recv_ad.sin_family = AF_INET;
recv_ad.sin_addr.s_addr = INADDR_ANY;
recv_ad.sin_port = htons((u_short)IconCtrlStruct.FloatParam[2]);
/* Bind local port and address to socket. */
if (bind(sd, (struct sockaddr *) &recv_ad, sizeof(struct sockaddr_in)) == -1) {
OpalPrint("%s: ERROR: Could not bind local port to socket\n", PROGNAME);
return EIO;
}
else
OpalPrint("%s: Local Port : %d\n", PROGNAME, (int) IconCtrlStruct.FloatParam[2]);
switch (proto) {
case UDP_PROTOCOL: /* Communication using UDP/IP protocol */
/* If sending to a multicast address */
if ((inet_addr(IconCtrlStruct.StringParam[0]) & inet_addr("240.0.0.0")) == inet_addr("224.0.0.0")) {
if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &TTL, sizeof(TTL)) == -1) {
OpalPrint("%s: ERROR: Could not set TTL for multicast send (%d)\n", PROGNAME, errno);
return EIO;
}
if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&LOOP, sizeof(LOOP)) == -1) {
OpalPrint("%s: ERROR: Could not set loopback for multicast send (%d)\n", PROGNAME, errno);
return EIO;
}
OpalPrint("%s: Configured socket for sending to multicast address\n", PROGNAME);
}
/* If receiving from a multicast group, register for it. */
if (inet_addr(IconCtrlStruct.StringParam[1]) > 0) {
if ((inet_addr(IconCtrlStruct.StringParam[1]) & inet_addr("240.0.0.0")) == inet_addr("224.0.0.0")) {
mreq.imr_multiaddr.s_addr = inet_addr(IconCtrlStruct.StringParam[1]);
mreq.imr_interface.s_addr = INADDR_ANY;
/* Have the multicast socket join the multicast group */
if (setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq)) == -1) {
OpalPrint("%s: ERROR: Could not join multicast group (%d)\n", PROGNAME, errno);
return EIO;
}
OpalPrint("%s: Added process to multicast group (%s)\n",
PROGNAME, IconCtrlStruct.StringParam[1]);
}
else {
OpalPrint("%s: WARNING: IP address for multicast group is not in multicast range. Ignored\n",
PROGNAME);
}
}
break;
case TCP_PROTOCOL: /* Communication using TCP/IP protocol */
OpalPrint("%s: Calling connect()\n", PROGNAME);
/* Connect to server to start data transmission */
rc = connect(sd, (struct sockaddr *) &send_ad, sizeof(send_ad));
if (rc < 0) {
OpalPrint("%s: ERROR: Call to connect() failed\n", PROGNAME);
return EIO;
}
break;
}
return EOK;
}
int SendPacket(char* DataSend, int datalength)
{
int err;
if(sd < 0)
return -1;
/* Send the packet */
if (proto == TCP_PROTOCOL)
err = send(sd, DataSend, datalength, 0);
else
err = sendto(sd, DataSend, datalength, 0, (struct sockaddr *)&send_ad, sizeof(send_ad));
return err;
}
int RecvPacket(char* DataRecv, int datalength, double timeout)
{
int len;
struct sockaddr_in client_ad;
socklen_t client_ad_size = sizeof(client_ad);
fd_set sd_set;
struct timeval tv;
if (sd < 0)
return -1;
/* Set the descriptor set for the select() call */
FD_ZERO(&sd_set);
FD_SET(sd, &sd_set);
/* Set the tv structure to the correct timeout value */
tv.tv_sec = (int) timeout;
tv.tv_usec = (int) ((timeout - tv.tv_sec) * 1000000);
/* Wait for a packet. We use select() to have a timeout. This is
* necessary when reseting the model so we don't wait indefinitely
* and prevent the process from exiting and freeing the port for
* a future instance (model load). */
switch (select(sd+1, &sd_set, (fd_set *) 0, (fd_set *) 0, &tv)) {
case -1: /* Error */
return -1;
case 0: /* We hit the timeout */
return 0;
default:
if (!(FD_ISSET(sd, &sd_set))) {
/* We received something, but it's not on "sd". Since sd is the only
* descriptor in the set... */
OpalPrint("%s: RecvPacket: God, is that You trying to reach me?\n", PROGNAME);
return -1;
}
}
/* Clear the DataRecv array (in case we receive an incomplete packet) */
memset(DataRecv, 0, datalength);
/* Perform the reception */
if (proto == TCP_PROTOCOL)
len = recv(sd, DataRecv, datalength, 0);
else
len = recvfrom(sd, DataRecv, datalength, 0, (struct sockaddr *) &client_ad, &client_ad_size);
return len;
}
int CloseSocket(Opal_GenAsyncParam_Ctrl IconCtrlStruct)
{
if (sd < 0) {
shutdown(sd, SHUT_RDWR);
close(sd);
}
return 0;
}
/** Helper functions for socket
*
* Code example of an asynchronous program. This program is started
* by the asynchronous controller and demonstrates how to send and
* receive data to and from the asynchronous icons and a UDP or TCP
* port.
*
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @author Mathieu Dubé-Dallaire
* @copyright 2014, Institute for Automation of Complex Power Systems, EONERC
* @copyright 2003, OPAL-RT Technologies inc
* @file
*/
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
/* Define RTLAB before including OpalPrint.h for messages to be sent
* to the OpalDisplay. Otherwise stdout will be used. */
#define RTLAB
#include "OpalPrint.h"
#include "AsyncApi.h"
#include "config.h"
#include "socket.h"
/* Globals variables */
struct sockaddr_in send_ad; /* Send address */
struct sockaddr_in recv_ad; /* Receive address */
int sd = -1; /* socket descriptor */
int proto = UDP_PROTOCOL;
int InitSocket(Opal_GenAsyncParam_Ctrl IconCtrlStruct)
{
struct ip_mreq mreq; /* Multicast group structure */
int socket_type;
int socket_proto;
unsigned char TTL = 1;
unsigned char LOOP = 0;
int rc;
proto = (int) IconCtrlStruct.FloatParam[0];
OpalPrint("%s: Version : %s\n", PROGNAME, VERSION);
switch (proto) {
case UDP_PROTOCOL: /* Communication using UDP/IP protocol */
socket_proto = IPPROTO_UDP;
socket_type = SOCK_DGRAM;
OpalPrint("%s: Protocol : UDP/IP\n", PROGNAME);
break;
case TCP_PROTOCOL: /* Communication using TCP/IP protocol */
socket_proto = IPPROTO_IP;
socket_type = SOCK_STREAM;
OpalPrint("%s: Protocol : TCP/IP\n", PROGNAME);
break;
default: /* Protocol is not recognized */
OpalPrint("%s: ERROR: Protocol (%d) not supported!\n", PROGNAME, proto);
return EINVAL;
}
OpalPrint("%s: Remote Address : %s\n", PROGNAME, IconCtrlStruct.StringParam[0]);
OpalPrint("%s: Remote Port : %d\n", PROGNAME, (int) IconCtrlStruct.FloatParam[1]);
/* Initialize the socket */
if ((sd = socket(AF_INET, socket_type, socket_proto)) < 0) {
OpalPrint("%s: ERROR: Could not open socket\n", PROGNAME);
return EIO;
}
/* Set the structure for the remote port and address */
memset(&send_ad, 0, sizeof(send_ad));
send_ad.sin_family = AF_INET;
send_ad.sin_addr.s_addr = inet_addr(IconCtrlStruct.StringParam[0]);
send_ad.sin_port = htons((u_short)IconCtrlStruct.FloatParam[1]);
/* Set the structure for the local port and address */
memset(&recv_ad, 0, sizeof(recv_ad));
recv_ad.sin_family = AF_INET;
recv_ad.sin_addr.s_addr = INADDR_ANY;
recv_ad.sin_port = htons((u_short)IconCtrlStruct.FloatParam[2]);
/* Bind local port and address to socket. */
if (bind(sd, (struct sockaddr *) &recv_ad, sizeof(struct sockaddr_in)) == -1) {
OpalPrint("%s: ERROR: Could not bind local port to socket\n", PROGNAME);
return EIO;
}
else
OpalPrint("%s: Local Port : %d\n", PROGNAME, (int) IconCtrlStruct.FloatParam[2]);
switch (proto) {
case UDP_PROTOCOL: /* Communication using UDP/IP protocol */
/* If sending to a multicast address */
if ((inet_addr(IconCtrlStruct.StringParam[0]) & inet_addr("240.0.0.0")) == inet_addr("224.0.0.0")) {
if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &TTL, sizeof(TTL)) == -1) {
OpalPrint("%s: ERROR: Could not set TTL for multicast send (%d)\n", PROGNAME, errno);
return EIO;
}
if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&LOOP, sizeof(LOOP)) == -1) {
OpalPrint("%s: ERROR: Could not set loopback for multicast send (%d)\n", PROGNAME, errno);
return EIO;
}
OpalPrint("%s: Configured socket for sending to multicast address\n", PROGNAME);
}
/* If receiving from a multicast group, register for it. */
if (inet_addr(IconCtrlStruct.StringParam[1]) > 0) {
if ((inet_addr(IconCtrlStruct.StringParam[1]) & inet_addr("240.0.0.0")) == inet_addr("224.0.0.0")) {
mreq.imr_multiaddr.s_addr = inet_addr(IconCtrlStruct.StringParam[1]);
mreq.imr_interface.s_addr = INADDR_ANY;
/* Have the multicast socket join the multicast group */
if (setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq)) == -1) {
OpalPrint("%s: ERROR: Could not join multicast group (%d)\n", PROGNAME, errno);
return EIO;
}
OpalPrint("%s: Added process to multicast group (%s)\n",
PROGNAME, IconCtrlStruct.StringParam[1]);
}
else {
OpalPrint("%s: WARNING: IP address for multicast group is not in multicast range. Ignored\n",
PROGNAME);
}
}
break;
case TCP_PROTOCOL: /* Communication using TCP/IP protocol */
OpalPrint("%s: Calling connect()\n", PROGNAME);
/* Connect to server to start data transmission */
rc = connect(sd, (struct sockaddr *) &send_ad, sizeof(send_ad));
if (rc < 0) {
OpalPrint("%s: ERROR: Call to connect() failed\n", PROGNAME);
return EIO;
}
break;
}
return EOK;
}
int SendPacket(char* DataSend, int datalength)
{
int err;
if(sd < 0)
return -1;
/* Send the packet */
if (proto == TCP_PROTOCOL)
err = send(sd, DataSend, datalength, 0);
else
err = sendto(sd, DataSend, datalength, 0, (struct sockaddr *)&send_ad, sizeof(send_ad));
return err;
}
int RecvPacket(char* DataRecv, int datalength, double timeout)
{
int len;
struct sockaddr_in client_ad;
socklen_t client_ad_size = sizeof(client_ad);
fd_set sd_set;
struct timeval tv;
if (sd < 0)
return -1;
/* Set the descriptor set for the select() call */
FD_ZERO(&sd_set);
FD_SET(sd, &sd_set);
/* Set the tv structure to the correct timeout value */
tv.tv_sec = (int) timeout;
tv.tv_usec = (int) ((timeout - tv.tv_sec) * 1000000);
/* Wait for a packet. We use select() to have a timeout. This is
* necessary when reseting the model so we don't wait indefinitely
* and prevent the process from exiting and freeing the port for
* a future instance (model load). */
switch (select(sd+1, &sd_set, (fd_set *) 0, (fd_set *) 0, &tv)) {
case -1: /* Error */
return -1;
case 0: /* We hit the timeout */
return 0;
default:
if (!(FD_ISSET(sd, &sd_set))) {
/* We received something, but it's not on "sd". Since sd is the only
* descriptor in the set... */
OpalPrint("%s: RecvPacket: God, is that You trying to reach me?\n", PROGNAME);
return -1;
}
}
/* Clear the DataRecv array (in case we receive an incomplete packet) */
memset(DataRecv, 0, datalength);
/* Perform the reception */
if (proto == TCP_PROTOCOL)
len = recv(sd, DataRecv, datalength, 0);
else
len = recvfrom(sd, DataRecv, datalength, 0, (struct sockaddr *) &client_ad, &client_ad_size);
return len;
}
int CloseSocket(Opal_GenAsyncParam_Ctrl IconCtrlStruct)
{
if (sd < 0) {
shutdown(sd, SHUT_RDWR);
close(sd);
}
return 0;
}

View file

@ -1,18 +1,18 @@
<?xml version="1.0" ?>
<Project>
<General>
<att_name>s2ss_tests</att_name>
<att_description>This is a project!</att_description>
<att_autosave>ON</att_autosave>
<att_filename>D:\msv\svo\opal\s2ss_tests\s2ss_tests.llp</att_filename>
</General>
<Models>
<Model>
<Path>
<Relative>models\send_receive\send_receive.mdl</Relative>
<Absolute>D:\msv\svo\opal\s2ss_tests\models\send_receive\send_receive.mdl</Absolute>
<UNC>D:\msv\svo\opal\s2ss_tests\models\send_receive\send_receive.mdl</UNC>
</Path>
</Model>
</Models>
</Project>
<?xml version="1.0" ?>
<Project>
<General>
<att_name>s2ss_tests</att_name>
<att_description>This is a project!</att_description>
<att_autosave>ON</att_autosave>
<att_filename>D:\msv\svo\opal\s2ss_tests\s2ss_tests.llp</att_filename>
</General>
<Models>
<Model>
<Path>
<Relative>models\send_receive\send_receive.mdl</Relative>
<Absolute>D:\msv\svo\opal\s2ss_tests\models\send_receive\send_receive.mdl</Absolute>
<UNC>D:\msv\svo\opal\s2ss_tests\models\send_receive\send_receive.mdl</UNC>
</Path>
</Model>
</Models>
</Project>

View file

@ -1,18 +0,0 @@
/** Compiled-in settings
*
* @file
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
* @copyright 2014-2015, Institute for Automation of Complex Power Systems, EONERC
* This file is part of S2SS. All Rights Reserved. Proprietary and confidential.
* Unauthorized copying of this file, via any medium is strictly prohibited.
*********************************************************************************/
#ifndef _CONFIG_H_
#define _CONFIG_H_
#define PROGNAME "S2SS"
#define VERSION "0.1"
#define MAX_VALUES 64
#endif /* _CONFIG_H_ */