diff --git a/clients/opal/models/send_receive/AsyncIP.mk b/clients/opal/models/send_receive/AsyncIP.mk new file mode 100644 index 000000000..8aa745365 --- /dev/null +++ b/clients/opal/models/send_receive/AsyncIP.mk @@ -0,0 +1,66 @@ +# Makefile. +# +# Author: Steffen Vogel +# SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University +# SPDX-License-Identifier: Apache-2.0 + +# Specify program name +PROGRAM = AsyncIP + +TARGET_RTLAB_ROOT ?= /usr/opalrt +RTLAB_ROOT = $(TARGET_RTLAB_ROOT) + +# Intel is the default compiler +RTLAB_INTEL_COMPILER ?= 0 +ifeq ($(RTLAB_INTEL_COMPILER),1) + CC = opicc +else + CC = gcc +endif + +LIB_TARGET = -lpthread -lrt -lm + +# Add Intel C library for compilation with gcc +ifeq ($(RTLAB_INTEL_COMPILER),0) + LIB_TARGET += -lirc -ldl +else + LD_OPTS += -diag-disable remark,warn +endif + +LD := $(CC) + +CC_OPTS = -std=c99 -D_GNU_SOURCE -MMD +LD_OPTS = +OBJS = main.o msg.o utils.o socket.o + +ifeq ($(DEBUG),1) + CC_OPTS += -g -D_DEBUG + LD_OPTS += -g +else + CC_OPTS += -O +endif + +ifneq ($(PROTOCOL),) + CC_OPTS += -DPROTOCOL=$(PROTOCOL) +endif + +INCPATH = -I. -I$(RTLAB_ROOT)/common/include_target +LIBPATH = -L. $(OPAL_LIBPATH) + +# The required libraries are transfered automatically in the model directory before compilation +LIBS := -lOpalAsyncApiCore -lOpalCore -lOpalUtils $(OPAL_LIBS) $(LIB_TARGET) +CFLAGS = $(CC_OPTS) $(INCPATH) +LDFLAGS = $(LD_OPTS) $(LIBPATH) + +all: $(PROGRAM) + +install: + \mkdir -p $(RTLAB_ROOT)/local + \chmod 755 $(RTLAB_ROOT/local + \cp -f $(PROGRAM) $(RTLAB_ROOT)/local + +clean: + \rm -f $(OBJS) $(PROGRAM) + +$(PROGRAM): $(OBJS) + $(LD) $(LDFLAGS) -o $@ $(OBJS) -Wl,--start-group $(LIBS) -Wl,--end-group diff --git a/clients/opal/models/send_receive/Makefile.mk b/clients/opal/models/send_receive/Makefile.mk deleted file mode 100644 index 1a0cf4a11..000000000 --- a/clients/opal/models/send_receive/Makefile.mk +++ /dev/null @@ -1,68 +0,0 @@ -# Makefile. -# -# Author: Steffen Vogel -# SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University -# SPDX-License-Identifier: Apache-2.0 - -TARGET = AsyncIP - -VPATH = src - -RTLAB_INTEL_COMPILER ?= 1 - -# Compiler selection -ifeq ($(RTLAB_INTEL_COMPILER),1) - CC = opicc - LD = opicpc -else - CC = gcc - LD = g++ - - INTEL_LIBS = -limf -lirc - INTEL_OBJS = compat.o -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 - -TARGET_LIB = -lpthread -lm -ldl -lutil -lrt $(INTEL_LIBS) - -LIBPATH = -L. $(OPAL_LIBPATH) -INCLUDES = -I. -Iinclude $(OPAL_INCPATH) - -ifneq ($(RTLAB_ROOT),) - INCLUDES += -I$(RTLAB_ROOT)/common/include_target -endif - -CC_OPTS = -std=c99 -D_GNU_SOURCE -MMD -LD_OPTS = -OBJS = main.o msg.o utils.o socket.o $(INTEL_OBJS) - -ifneq ($(PROTOCOL),) - CC_OPTS += -DPROTOCOL=$(PROTOCOL) -endif - -ADDLIB = -lOpalCore -lOpalUtils -LIBS = -lOpalAsyncApiCore $(ADDLIB) $(TARGET_LIB) $(OPAL_LIBS) - -CFLAGS = -c $(CC_OPTS) $(CC_DEBUG_OPTS) $(INCLUDES) -LDFLAGS = $(LD_OPTS) $(LD_DEBUG_OPTS) $(LIBPATH) - -all: $(TARGET) - -install: $(TARGET) - install -m 0755 -D -t $(DESTDIR)$(PREFIX)/bin $(TARGET) - -clean: - rm -f $(OBJS) $(OBJS:%.o=%.d) $(TARGET) - -$(TARGET): $(OBJS) - $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) - --include $(wildcard *.d) diff --git a/clients/opal/models/send_receive/send_receive.llm b/clients/opal/models/send_receive/send_receive.llm index 51ab8a042..6244c5ac1 100644 --- a/clients/opal/models/send_receive/send_receive.llm +++ b/clients/opal/models/send_receive/send_receive.llm @@ -39,7 +39,7 @@ INTERNAL_IGN_SOURCE_FILE=sfun_gen_async_ctrl.c sfun_recv_async.c sfun_send_async INTERNAL_LIBRARY2=-lOpalAsyncApiR2014b INTERNAL_LIBRARY3=-lOpalAsyncApiCore [ExtraPutFilesComp] -Makefile.mk=Ascii +AsyncIP.mk=Ascii include\config.h=Ascii include\msg.h=Ascii include\msg_format.h=Ascii @@ -112,4 +112,3 @@ sm_send_receive_DEBUG=OFF sm_send_receive_XHP_ENABLE=FALSE [UserEnvVars] PROTOCOL=VILLAS -RTLAB_INTEL_COMPILER=1 diff --git a/clients/opal/models/send_receive/src/compat.c b/clients/opal/models/send_receive/src/compat.c deleted file mode 100644 index d127fcca3..000000000 --- a/clients/opal/models/send_receive/src/compat.c +++ /dev/null @@ -1,29 +0,0 @@ -/* Compatibility code for GCC. - * - * OPAL-RT's libSystem.a links against some Intel - * - * Author: Steffen Vogel - * SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -size_t __intel_sse2_strlen(const char *s) { return strlen(s); } - -void *_intel_fast_memset(void *b, int c, size_t len) { - return memset(b, c, len); -} - -void *_intel_fast_memcpy(void *restrict dst, const void *restrict src, - size_t n) { - return memcpy(dst, src, n); -} - -int _intel_fast_memcmp(const void *s1, const void *s2, size_t n) { - return memcmp(s1, s2, n); -} - -void *_intel_fast_memmove(void *dest, const void *src, size_t num) { - return memmove(dest, src, num); -} diff --git a/clients/opal/models/send_receive/src/main.asv b/clients/opal/models/send_receive/src/main.asv deleted file mode 100644 index dac4d0759..000000000 --- a/clients/opal/models/send_receive/src/main.asv +++ /dev/null @@ -1,335 +0,0 @@ -/** Main routine of AsyncIP. - * - * Author: Steffen Vogel - * SPDX-FileCopyrightText: 2014-2023 Institute for Automation of Complex Power Systems, RWTH Aachen University - * SPDX-License-Identifier: Apache-2.0 - *********************************************************************************/ - -/* Standard ANSI C headers needed for this program */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* 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 "socket.h" -#include "utils.h" - -#if PROTOCOL == VILLAS - #include "msg.h" - #include "msg_format.h" -#endif - -/* 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] - -/* Global Variables */ -struct socket skt; - -static void * SendToIPPort(void *arg) -{ - unsigned int ModelState, SendID = 1, Sequence = 0; - int nbSend = 0, ret, cnt, len; - - /* Data from OPAL-RT model */ - double mdldata[MAX_VALUES]; - int mdldata_size; - -#if PROTOCOL == VILLAS - char buf[MSG_LEN(MAX_VALUES)]; - struct msg *msg = (struct msg *) buf; -#elif PROTOCOL == GTNET_SKT - char buf[MAX_VALUES * sizeof(float)]; - float *msg = (float *) buf; -#endif - - OpalPrint("%s: SendToIPPort thread started\n", PROGNAME); - - OpalGetNbAsyncSendIcon(&nbSend); - if (nbSend < 1) { - OpalPrint("%s: SendToIPPort: No transimission block for this controller. Stopping thread.\n", PROGNAME); - return NULL; - } - - do { - /* This call unblocks when the 'Data Ready' line of a send icon is asserted. */ - ret = OpalWaitForAsyncSendRequest(&SendID); - if (ret != EOK) { - ModelState = OpalGetAsyncModelState(); - if ((ModelState != STATE_RESET) && (ModelState != STATE_STOP)) { - OpalSetAsyncSendIconError(ret, SendID); - OpalPrint("%s: OpalWaitForAsyncSendRequest(), errno %d\n", PROGNAME, ret); - } - - continue; - } - - /* No errors encountered yet */ - OpalSetAsyncSendIconError(0, SendID); - - /* Get the size of the data being sent by the unblocking SendID */ - OpalGetAsyncSendIconDataLength(&mdldata_size, SendID); - cnt = mdldata_size / sizeof(double); - if (cnt > MAX_VALUES) { - OpalPrint("%s: Number of signals for SendID=%d exceeds allowed maximum (%d)\n", - PROGNAME, SendID, MAX_VALUES); - return NULL; - } - - /* Read data from the model */ - OpalGetAsyncSendIconData(mdldata, mdldata_size, SendID); - -#if PROTOCOL == VILLAS - /* Get current time */ - struct timespec now; - clock_gettime(CLOCK_REALTIME, &now); - - msg->length = mdldata_size / sizeof(double); - msg->sequence = Sequence++; - msg->ts.sec = now.tv_sec; - msg->ts.nsec = now.tv_nsec; - - for (int i = 0; i < msg->length; i++) - msg->data[i].f = (float) mdldata[i]; - - msg_hton(msg); - - len = MSG_LEN(msg->length); -#elif PROTOCOL == GTNET_SKT - uint32_t *imsg = (uint32_t *) msg; - for (int i = 0; i < cnt; i++) { - msg[i] = (float) mdldata[i]; - imsg[i] = htonl(imsg[i]); - } - - len = mdldata_size / sizeof(double) * sizeof(float); -#else - #error Unknown protocol -#endif - - /* Perform the actual write to the ip port */ - ret = socket_send(&skt, (char *) msg, len); - if (ret < 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); - - return NULL; -} - -static void * RecvFromIPPort(void *arg) -{ - unsigned int ModelState, RecvID = 1; - int nbRecv = 0, ret, cnt; - - /* Data from OPAL-RT model */ - double mdldata[MAX_VALUES]; - int mdldata_size; - -#if PROTOCOL == VILLAS - char buf[MSG_LEN(MAX_VALUES)]; - struct msg *msg = (struct msg *) buf; -#elif PROTOCOL == GTNET_SKT - char buf[MAX_VALUES * sizeof(float)]; - float *msg = (float *) buf; -#else - #error Unknown protocol -#endif - - OpalPrint("%s: RecvFromIPPort thread started\n", PROGNAME); - - OpalGetNbAsyncRecvIcon(&nbRecv); - if (nbRecv < 1) { - OpalPrint("%s: RecvFromIPPort: No reception block for this controller. Stopping thread.\n", PROGNAME); - return NULL; - } - - do { - /* Receive message */ - ret = socket_recv(&skt, (char *) msg, sizeof(buf), 1.0); - if (ret < 1) { - ModelState = OpalGetAsyncModelState(); - if ((ModelState != STATE_RESET) && (ModelState != STATE_STOP)) { - if (ret == 0) /* timeout, so we continue silently */ - OpalPrint("%s: Timeout while waiting for data\n", PROGNAME, errno); - if (ret == -1) /* a more serious error, so we print it */ - OpalPrint("%s: Error %d while waiting for data\n", PROGNAME, errno); - - continue; - } - break; - } - - /* Get the number of signals to send back to the model */ - OpalGetAsyncRecvIconDataLength(&mdldata_size, RecvID); - cnt = mdldata_size / sizeof(double); - if (cnt > MAX_VALUES) { - OpalPrint("%s: Number of signals for RecvID=%d (%d) exceeds allowed maximum (%d)\n", - PROGNAME, RecvID, cnt, MAX_VALUES); - return NULL; - } - -#if PROTOCOL == VILLAS - msg_ntoh(msg); - - ret = msg_verify(msg); - if (ret) { - OpalPrint("%s: Skipping invalid packet\n", PROGNAME); - continue; - } - - if (cnt > msg->length) { - OpalPrint("%s: Number of signals for RecvID=%d (%d) exceeds what was received (%d)\n", - PROGNAME, RecvID, cnt, msg->length); - } - - for (int i = 0; i < msg->length; i++) { - mdldata[i] = (double) msg->data[i].f; - printf("Data rcvd from VILLAS %f\n", mdldata[i]); - } - - /* Update OPAL model */ - OpalSetAsyncRecvIconStatus(msg->sequence, RecvID); /* Set the Status to the message ID */ -#elif PROTOCOL == GTNET_SKT - uint32_t *imsg = (uint32_t *) msg; - for (int i = 0; i < cnt; i++) - imsg[i] = ntohl(imsg[i]); - - printf("Protocol GTNET_SKT\n"); - for (int i = 0; i < cnt; i++) { - mdldata[i] = (double) msg[i]; - printf("Data rcvd from GTNET_SKT %f\n", mdldata[i]); - } -#else - #error Unknown protocol -#endif - - OpalSetAsyncRecvIconError(0, RecvID); /* Set the Error to 0 */ - - 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); - - return NULL; -} - -int main(int argc, char *argv[]) -{ - /* @todo remove after testing */ - printf("*****************Starting the Application****************\n"); - FILE * testfile = fopen ("testfile.txt","w"); - if (testfile!=NULL) - { - fputs ("test file to check if main runs", testfile); - fclose (testfile); - } - - int ret; - - Opal_GenAsyncParam_Ctrl IconCtrlStruct; - - pthread_t tid_send, tid_recv; - - OpalPrint("%s: This is %s client version %s\n", PROGNAME, PROGNAME, VERSION); - - /* 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. */ - ret = OpalSystemCtrl_Register(PRINT_SHMEM_NAME); - if (ret != EOK) { - printf("%s: ERROR: OpalPrint() access not available\n", PROGNAME); - exit(EXIT_FAILURE); - } - - /* Open Share Memory created by the model. */ - ret = OpalOpenAsyncMem(ASYNC_SHMEM_SIZE, ASYNC_SHMEM_NAME); - if (ret != EOK) { - OpalPrint("%s: ERROR: Model shared memory not available\n", PROGNAME); - exit(EXIT_FAILURE); - } - - AssignProcToCpu0(); - - /* Get IP Controler Parameters (ie: ip address, port number...) and - * initialize the device on the QNX node. */ - memset(&IconCtrlStruct, 0, sizeof(IconCtrlStruct)); - - ret = OpalGetAsyncCtrlParameters(&IconCtrlStruct, sizeof(IconCtrlStruct)); - if (ret != EOK) { - OpalPrint("%s: ERROR: Could not get controller parameters (%d).\n", PROGNAME, ret); - exit(EXIT_FAILURE); - } - - /* Initialize socket */ - ret = socket_init(&skt, IconCtrlStruct); - if (ret != EOK) { - OpalPrint("%s: ERROR: Initialization failed.\n", PROGNAME); - exit(EXIT_FAILURE); - } - - /* Start send/receive threads */ - ret = pthread_create(&tid_send, NULL, SendToIPPort, NULL); - if (ret == -1) - OpalPrint("%s: ERROR: Could not create thread (SendToIPPort), errno %d\n", PROGNAME, errno); - - ret = pthread_create(&tid_recv, NULL, RecvFromIPPort, NULL); - if (ret == -1) - OpalPrint("%s: ERROR: Could not create thread (RecvFromIPPort), errno %d\n", PROGNAME, errno); - - /* Wait for both threads to finish */ - ret = pthread_join(tid_send, NULL); - if (ret != 0) - OpalPrint("%s: ERROR: pthread_join (SendToIPPort), errno %d\n", PROGNAME, ret); - - ret = pthread_join(tid_recv, NULL); - if (ret != 0) - OpalPrint("%s: ERROR: pthread_join (RecvFromIPPort), errno %d\n", PROGNAME, ret); - - /* Close the ip port and shared memories */ - socket_close(&skt, IconCtrlStruct); - - OpalCloseAsyncMem (ASYNC_SHMEM_SIZE, ASYNC_SHMEM_NAME); - OpalSystemCtrl_UnRegister(PRINT_SHMEM_NAME); - - return 0; -}