Merge branch 'V1.5_RT_Development' into v1.5
commit
4ed4e76640
@ -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
|
||||||
|
)
|
||||||
|
|
||||||
|
|
@ -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)
|
@ -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 <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
@ -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
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* sv_subscriber_example.c
|
||||||
|
*
|
||||||
|
* Example program for Sampled Values (SV) subscriber
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hal_thread.h"
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#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;
|
||||||
|
}
|
Loading…
Reference in New Issue