From 8187e434eeb237f65f12b402c50baf143805aba9 Mon Sep 17 00:00:00 2001 From: Ben Haines Date: Mon, 5 Jun 2023 22:37:16 -0700 Subject: [PATCH] Add RT examples --- examples/goose_subscriber_RT/CMakeLists.txt | 20 ++++ examples/goose_subscriber_RT/Makefile | 17 ++++ .../goose_subscriber_example_RT.c | 98 +++++++++++++++++++ examples/sv_subscriber_RT/CMakeLists.txt | 20 ++++ examples/sv_subscriber_RT/Makefile | 21 ++++ .../sv_subscriber_example_RT.c | 95 ++++++++++++++++++ 6 files changed, 271 insertions(+) create mode 100644 examples/goose_subscriber_RT/CMakeLists.txt create mode 100644 examples/goose_subscriber_RT/Makefile create mode 100644 examples/goose_subscriber_RT/goose_subscriber_example_RT.c create mode 100644 examples/sv_subscriber_RT/CMakeLists.txt create mode 100644 examples/sv_subscriber_RT/Makefile create mode 100644 examples/sv_subscriber_RT/sv_subscriber_example_RT.c diff --git a/examples/goose_subscriber_RT/CMakeLists.txt b/examples/goose_subscriber_RT/CMakeLists.txt new file mode 100644 index 00000000..e6ad90ea --- /dev/null +++ b/examples/goose_subscriber_RT/CMakeLists.txt @@ -0,0 +1,20 @@ + +set(goose_subscriber_example_SRCS + goose_subscriber_example_RT.c +) + +IF(MSVC) + +set_source_files_properties(${goose_subscriber_example_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(MSVC) + +add_executable(goose_subscriber_example_RT + ${goose_subscriber_example_SRCS} +) + +target_link_libraries(goose_subscriber_example_RT + iec61850 +) + + diff --git a/examples/goose_subscriber_RT/Makefile b/examples/goose_subscriber_RT/Makefile new file mode 100644 index 00000000..121b024e --- /dev/null +++ b/examples/goose_subscriber_RT/Makefile @@ -0,0 +1,17 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = goose_subscriber_example_RT +PROJECT_SOURCES = goose_subscriber_example_RT.c + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) diff --git a/examples/goose_subscriber_RT/goose_subscriber_example_RT.c b/examples/goose_subscriber_RT/goose_subscriber_example_RT.c new file mode 100644 index 00000000..32cd8687 --- /dev/null +++ b/examples/goose_subscriber_RT/goose_subscriber_example_RT.c @@ -0,0 +1,98 @@ +/* + * goose_subscriber_example.c + * + * This is an example for a standalone GOOSE subscriber + * + * Has to be started as root in Linux. + * + * BPH - 11-8-21 + * Adapted from original goose publlisher example to implement realtime threading and priorities + * + */ + +#include "goose_receiver.h" +#include "goose_subscriber.h" +#include "hal_thread.h" +#include "linked_list.h" + +#include +#include +#include + +static int running = 1; + +static void +sigint_handler(int signalId) +{ + running = 0; +} + +static void +gooseListener(GooseSubscriber subscriber, void* parameter) +{ + printf("GOOSE event:\n"); + printf(" stNum: %u sqNum: %u\n", GooseSubscriber_getStNum(subscriber), + GooseSubscriber_getSqNum(subscriber)); + printf(" timeToLive: %u\n", GooseSubscriber_getTimeAllowedToLive(subscriber)); + + uint64_t timestamp = GooseSubscriber_getTimestamp(subscriber); + + printf(" timestamp: %u.%u\n", (uint32_t) (timestamp / 1000), (uint32_t) (timestamp % 1000)); + printf(" message is %s\n", GooseSubscriber_isValid(subscriber) ? "valid" : "INVALID"); + + MmsValue* values = GooseSubscriber_getDataSetValues(subscriber); + + char buffer[1024]; + + MmsValue_printToBuffer(values, buffer, 1024); + + printf(" allData: %s\n", buffer); +} + +int +main(int argc, char** argv) +{ + // BPH Notes: Single receiver on interface with potentially multiple subscribers. + GooseReceiver receiver = GooseReceiver_create(); //BPH Notes: Mallocs Receiver Struct and Eth Buffer + + if (argc > 1) { + printf("Set interface id: %s\n", argv[1]); + GooseReceiver_setInterfaceId(receiver, argv[1]); + } + else { + printf("Using interface eth0\n"); + GooseReceiver_setInterfaceId(receiver, "eth0"); + } + + GooseSubscriber subscriber = GooseSubscriber_create("simpleIOGenericIO/LLN0$GO$gcbAnalogValues", NULL); + + uint8_t dstMac[6] = {0x01,0x0c,0xcd,0x01,0x00,0x01}; + GooseSubscriber_setDstMac(subscriber, dstMac); + GooseSubscriber_setAppId(subscriber, 1000); + + // BPH Notes: Attach listner function to subscriber struct, called when goose received that matches + GooseSubscriber_setListener(subscriber, gooseListener, NULL); + + // BPH Notes: add subscriber struct to receiver list + GooseReceiver_addSubscriber(receiver, subscriber); + + // BPH Notes: call when all subscribers added + GooseReceiver_start_RT(receiver); // Create receive thread with RT priority + + if (GooseReceiver_isRunning(receiver)) { + signal(SIGINT, sigint_handler); + + while (running) { + Thread_sleep(100); + } + } + else { + printf("Failed to start GOOSE subscriber. Reason can be that the Ethernet interface doesn't exist or root permission are required.\n"); + } + + GooseReceiver_stop(receiver); + + GooseReceiver_destroy(receiver); + + return 0; +} diff --git a/examples/sv_subscriber_RT/CMakeLists.txt b/examples/sv_subscriber_RT/CMakeLists.txt new file mode 100644 index 00000000..0a4aeeec --- /dev/null +++ b/examples/sv_subscriber_RT/CMakeLists.txt @@ -0,0 +1,20 @@ + +set(sv_subscriber_example_SRCS + sv_subscriber_example_RT.c +) + +IF(MSVC) + +set_source_files_properties(${sv_subscriber_example_SRCS} + PROPERTIES LANGUAGE CXX) +ENDIF(MSVC) + +add_executable(sv_subscriber_example_RT + ${sv_subscriber_example_SRCS} +) + +target_link_libraries(sv_subscriber_example_RT +) + + + diff --git a/examples/sv_subscriber_RT/Makefile b/examples/sv_subscriber_RT/Makefile new file mode 100644 index 00000000..7ccd2981 --- /dev/null +++ b/examples/sv_subscriber_RT/Makefile @@ -0,0 +1,21 @@ +LIBIEC_HOME=../.. + +PROJECT_BINARY_NAME = sv_subscriber_RT +PROJECT_SOURCES += sv_subscriber_example_RT.c + +INCLUDES += -I. + +include $(LIBIEC_HOME)/make/target_system.mk +include $(LIBIEC_HOME)/make/stack_includes.mk + +all: $(PROJECT_BINARY_NAME) + +include $(LIBIEC_HOME)/make/common_targets.mk + +$(PROJECT_BINARY_NAME): $(PROJECT_SOURCES) $(LIB_NAME) + $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROJECT_BINARY_NAME) $(PROJECT_SOURCES) $(INCLUDES) $(LIB_NAME) $(LDLIBS) + +clean: + rm -f $(PROJECT_BINARY_NAME) + + diff --git a/examples/sv_subscriber_RT/sv_subscriber_example_RT.c b/examples/sv_subscriber_RT/sv_subscriber_example_RT.c new file mode 100644 index 00000000..10268e18 --- /dev/null +++ b/examples/sv_subscriber_RT/sv_subscriber_example_RT.c @@ -0,0 +1,95 @@ +/* + * sv_subscriber_example.c + * + * Example program for Sampled Values (SV) subscriber + * + */ + +#include "hal_thread.h" +#include +#include +#include "sv_subscriber.h" + + +static bool running = true; + +void sigint_handler(int signalId) +{ + running = 0; +} + + +/* Callback handler for received SV messages */ +static void +svUpdateListener (SVSubscriber subscriber, void* parameter, SVSubscriber_ASDU asdu) +{ + printf("svUpdateListener called\n"); + + const char* svID = SVSubscriber_ASDU_getSvId(asdu); + + if (svID != NULL) + printf(" svID=(%s)\n", svID); + + printf(" smpCnt: %i\n", SVSubscriber_ASDU_getSmpCnt(asdu)); + printf(" confRev: %u\n", SVSubscriber_ASDU_getConfRev(asdu)); + + /* + * Access to the data requires a priori knowledge of the data set. + * For this example we assume a data set consisting of FLOAT32 values. + * A FLOAT32 value is encoded as 4 bytes. You can find the first FLOAT32 + * value at byte position 0, the second value at byte position 4, the third + * value at byte position 8, and so on. + * + * To prevent damages due configuration, please check the length of the + * data block of the SV message before accessing the data. + */ + if (SVSubscriber_ASDU_getDataSize(asdu) >= 8) { + printf(" DATA[0]: %f\n", SVSubscriber_ASDU_getFLOAT32(asdu, 0)); + printf(" DATA[1]: %f\n", SVSubscriber_ASDU_getFLOAT32(asdu, 4)); + } +} + +int +main(int argc, char** argv) +{ + SVReceiver receiver = SVReceiver_create(); + + if (argc > 1) { + SVReceiver_setInterfaceId(receiver, argv[1]); + printf("Set interface id: %s\n", argv[1]); + } + else { + printf("Using interface eth0\n"); + SVReceiver_setInterfaceId(receiver, "eth0"); + } + + /* Create a subscriber listening to SV messages with APPID 4000h */ + SVSubscriber subscriber = SVSubscriber_create(NULL, 0x4000); + + /* Install a callback handler for the subscriber */ + SVSubscriber_setListener(subscriber, svUpdateListener, NULL); + + /* Connect the subscriber to the receiver */ + SVReceiver_addSubscriber(receiver, subscriber); + + /* Start listening to SV messages - starts a new receiver background thread */ + SVReceiver_start_RT(receiver); + + + if (SVReceiver_isRunning(receiver)) { + signal(SIGINT, sigint_handler); + + while (running) + Thread_sleep(1); + + /* Stop listening to SV messages */ + SVReceiver_stop(receiver); + } + else { + printf("Failed to start SV subscriber. Reason can be that the Ethernet interface doesn't exist or root permission are required.\n"); + } + + /* Cleanup and free resources */ + SVReceiver_destroy(receiver); + return 0; +}