Compare commits
38 commits
master
...
ethernet-h
Author | SHA1 | Date | |
---|---|---|---|
694866cf02 | |||
dfd077c4c2 | |||
8a83b535a9 | |||
979656094d | |||
967e6ef5b3 | |||
20f654bbc3 | |||
63b6da6ae7 | |||
646c9cf073 | |||
b6cf079a94 | |||
dec12b61a8 | |||
c082f09aef | |||
89661b471f | |||
d771444904 | |||
1adcd6bcfb | |||
![]() |
f7b04a02ed | ||
![]() |
87583f5859 | ||
![]() |
bc6b7e68a8 | ||
![]() |
ba985ec2b0 | ||
![]() |
3b941ca577 | ||
ddae3c70ee | |||
![]() |
5d03e77343 | ||
![]() |
4cbaa6a7c1 | ||
![]() |
197a0b853f | ||
![]() |
180e5e7f26 | ||
e95b321d12 | |||
60c7d3a75f | |||
628641cabb | |||
1d8d6211ca | |||
dffe219303 | |||
581bd6e9af | |||
403c3a9e93 | |||
064bfa902e | |||
4fb3141088 | |||
02bc54a8c2 | |||
fc6e3892c6 | |||
3047681854 | |||
09d5daf0b5 | |||
![]() |
c291db5d95 |
24 changed files with 748 additions and 190 deletions
25
.travis.yml
Normal file
25
.travis.yml
Normal file
|
@ -0,0 +1,25 @@
|
|||
language: c
|
||||
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- cmake
|
||||
- swig
|
||||
- libsqlite3-dev
|
||||
- python-dev
|
||||
|
||||
before_install:
|
||||
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then
|
||||
brew update;
|
||||
brew install swig python sqlite;
|
||||
fi
|
||||
- mkdir -p build && cd build
|
||||
|
||||
script:
|
||||
- cmake .. -DBUILD_PYTHON_BINDINGS=ON
|
||||
- make
|
||||
- make test
|
|
@ -2,9 +2,9 @@ cmake_minimum_required(VERSION 2.8)
|
|||
|
||||
# automagically detect if we should cross-compile
|
||||
if(DEFINED ENV{TOOLCHAIN})
|
||||
set(CMAKE_C_COMPILER $ENV{TOOLCHAIN}gcc)
|
||||
set(CMAKE_CXX_COMPILER $ENV{TOOLCHAIN}g++)
|
||||
set(CMAKE_AR "$ENV{TOOLCHAIN}ar" CACHE FILEPATH "CW archiver" FORCE)
|
||||
set(CMAKE_C_COMPILER $ENV{TOOLCHAIN}gcc)
|
||||
set(CMAKE_CXX_COMPILER $ENV{TOOLCHAIN}g++)
|
||||
set(CMAKE_AR "$ENV{TOOLCHAIN}ar" CACHE FILEPATH "CW archiver" FORCE)
|
||||
endif()
|
||||
|
||||
project(libiec61850)
|
||||
|
@ -32,20 +32,15 @@ option(BUILD_PYTHON_BINDINGS "Build Python bindings" OFF)
|
|||
|
||||
option(CONFIG_MMS_SINGLE_THREADED "Compile for single threaded version" ON)
|
||||
option(CONFIG_MMS_THREADLESS_STACK "Optimize stack for threadless operation (warning: single- or multi-threaded server will not work!)" OFF)
|
||||
|
||||
# choose the library features which shall be included
|
||||
option(CONFIG_ACTIVATE_TCP_KEEPALIVE "Activate TCP keepalive" ON)
|
||||
option(CONFIG_INCLUDE_GOOSE_SUPPORT "Build with GOOSE support" ON)
|
||||
|
||||
# choose the library features which shall be included
|
||||
option(CONFIG_IEC61850_CONTROL_SERVICE "Build with support for IEC 61850 control features" ON)
|
||||
|
||||
option(CONFIG_IEC61850_REPORT_SERVICE "Build with support for IEC 61850 reporting services" ON)
|
||||
|
||||
option(CONFIG_IEC61850_LOG_SERVICE "Build with support for IEC 61850 logging services" ON)
|
||||
|
||||
option(CONFIG_IEC61850_SETTING_GROUPS "Build with support for IEC 61850 setting group services" ON)
|
||||
|
||||
option(CONFIG_ACTIVATE_TCP_KEEPALIVE "Activate TCP keepalive" ON)
|
||||
|
||||
set(CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE "8000" CACHE STRING "Default buffer size for buffered reports in byte" )
|
||||
|
||||
# advanced options
|
||||
|
@ -63,22 +58,23 @@ option(DEBUG_MMS_CLIENT "Enable MMS CLIENT printf debugging" OFF)
|
|||
|
||||
include_directories(
|
||||
${CMAKE_CURRENT_BINARY_DIR}/config
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/common/inc
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/goose
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/sampled_values
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/hal/inc
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/iec61850/inc
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/iec61850/inc_private
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/mms/inc
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/mms/inc_private
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/mms/iso_mms/asn1c
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/logging
|
||||
src/common/inc
|
||||
src/goose
|
||||
src/sampled_values
|
||||
src/hal/inc
|
||||
src/iec61850/inc
|
||||
src/iec61850/inc_private
|
||||
src/mms/inc
|
||||
src/mms/inc_private
|
||||
src/mms/iso_mms/asn1c
|
||||
src/logging
|
||||
)
|
||||
|
||||
set(API_HEADERS
|
||||
src/hal/inc/hal_time.h
|
||||
src/hal/inc/hal_thread.h
|
||||
src/hal/inc/hal_filesystem.h
|
||||
src/hal/inc/hal_ethernet.h
|
||||
src/hal/inc/platform_endian.h
|
||||
src/common/inc/libiec61850_common_api.h
|
||||
src/common/inc/libiec61850_platform_includes.h
|
||||
|
@ -114,42 +110,45 @@ set(API_HEADERS
|
|||
${CMAKE_CURRENT_BINARY_DIR}/config/stack_config.h
|
||||
)
|
||||
|
||||
IF(MSVC)
|
||||
include_directories(
|
||||
src/vs
|
||||
)
|
||||
ENDIF(MSVC)
|
||||
if(MSVC)
|
||||
include_directories(
|
||||
src/vs
|
||||
)
|
||||
endif(MSVC)
|
||||
|
||||
# write the detected stuff to this file
|
||||
configure_file(${CMAKE_CURRENT_LIST_DIR}/config/stack_config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config/stack_config.h)
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_LIST_DIR}/config/stack_config.h.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/config/stack_config.h
|
||||
)
|
||||
|
||||
if(BUILD_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
add_subdirectory(examples)
|
||||
endif(BUILD_EXAMPLES)
|
||||
|
||||
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/src)
|
||||
|
||||
INSTALL(FILES ${API_HEADERS} DESTINATION include/libiec61850 COMPONENT Development)
|
||||
install(FILES ${API_HEADERS} DESTINATION include/libiec61850 COMPONENT Development)
|
||||
|
||||
IF(BUILD_PYTHON_BINDINGS)
|
||||
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/pyiec61850)
|
||||
ENDIF(BUILD_PYTHON_BINDINGS)
|
||||
if(BUILD_PYTHON_BINDINGS)
|
||||
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/pyiec61850)
|
||||
endif(BUILD_PYTHON_BINDINGS)
|
||||
|
||||
IF(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake")
|
||||
INCLUDE(InstallRequiredSystemLibraries)
|
||||
|
||||
SET(CPACK_PACKAGE_DESCRIPTION "IEC 61850 MMS/GOOSE client and server library")
|
||||
SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "IEC 61850 MMS/GOOSE client and server library")
|
||||
SET(CPACK_PACKAGE_VENDOR "MZ Automation GmbH")
|
||||
SET(CPACK_PACKAGE_CONTACT "info@libiec61850.com")
|
||||
SET(CPACK_PACKAGE_VERSION_MAJOR "${LIB_VERSION_MAJOR}")
|
||||
SET(CPACK_PACKAGE_VERSION_MINOR "${LIB_VERSION_MINOR}")
|
||||
SET(CPACK_PACKAGE_VERSION_PATCH "${LIB_VERSION_PATCH}")
|
||||
SET(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}_${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}_${CMAKE_SYSTEM_PROCESSOR}")
|
||||
SET(CPACK_SOURCE_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}_${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
|
||||
|
||||
SET(CPACK_COMPONENTS_ALL Libraries Development Applications)
|
||||
#set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CMAKE_PROJECT_NAME}")
|
||||
INCLUDE(CPack)
|
||||
|
||||
ENDIF(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake")
|
||||
if(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake")
|
||||
include(InstallRequiredSystemLibraries)
|
||||
|
||||
set(CPACK_PACKAGE_DESCRIPTION "IEC 61850 MMS/GOOSE client and server library")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "IEC 61850 MMS/GOOSE client and server library")
|
||||
set(CPACK_PACKAGE_VENDOR "MZ Automation GmbH")
|
||||
set(CPACK_PACKAGE_CONTACT "info@libiec61850.com")
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR "${LIB_VERSION_MAJOR}")
|
||||
set(CPACK_PACKAGE_VERSION_MINOR "${LIB_VERSION_MINOR}")
|
||||
set(CPACK_PACKAGE_VERSION_PATCH "${LIB_VERSION_PATCH}")
|
||||
set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}_${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}_${CMAKE_SYSTEM_PROCESSOR}")
|
||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}_${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
|
||||
|
||||
set(CPACK_COMPONENTS_ALL Libraries Development Applications)
|
||||
#set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CMAKE_PROJECT_NAME}")
|
||||
|
||||
include(CPack)
|
||||
endif(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake")
|
||||
|
|
14
README.md
14
README.md
|
@ -1,5 +1,7 @@
|
|||
# README libIEC61850
|
||||
|
||||
[](https://travis-ci.org/mz-automation/libiec61850)
|
||||
|
||||
This file is part of the documentation of **libIEC61850**. More documentation can be found online at http://libiec61850.com or in the provided doxygen documentation. Also consider to review the examples to understand how to use the library
|
||||
|
||||
Content:
|
||||
|
@ -73,15 +75,17 @@ To build the library and run libiec61850 applications with GOOSE support on Wind
|
|||
|
||||
## Building with the cmake build script
|
||||
|
||||
With the help of the cmake build script it is possible to create platform independet project descriptions and let cmake create specific project or build files for other tools like Make or Visual Studio.
|
||||
With the help of the cmake build script it is possible to create platform independent project descriptions and let cmake create specific project or build files for other tools like Make or Visual Studio.
|
||||
|
||||
If you have cmake installed fire up a command line (cmd.exe) and create a new subdirectory in the libiec61850 folder. Change to this subdirectory. Then you can invoke cmake. As an command line argument you have to supply a "generator" that is used by cmake to create the project file for the actual build tool (in our case Visual Studio).
|
||||
If you have cmake installed fire up a command line (cmd.exe) and create a new subdirectory in the libiec61850 folder. Change to this subdirectory. Then you can invoke cmake. As an command line argument you have to supply a "generator" that is used by cmake to create the project file for the actual build tool (in our case Visual Studio 2015).
|
||||
|
||||
`cmake -G "Visual Studio 11" ..`
|
||||
`cmake -G "Visual Studio 14 2015" ..`
|
||||
|
||||
will instruct cmake to create a "solution" for Visual Studio 2012. To do the same thing for Visual Studio 2010 type
|
||||
will instruct cmake to create a "solution" for Visual Studio 2015. The resulting project files will be 32 bit.
|
||||
|
||||
`cmake -G "Visual Studio 10" ..`
|
||||
To build 64 bit libraries the "Win64" generator option has to be added.
|
||||
|
||||
`cmake -G "Visual Studio 14 2015 Win64" ..`
|
||||
|
||||
Note: The ".." at the end of the command line tells cmake where to find the main build script file (called CMakeLists.txt). This should point to the folder libiec61850 which is in our case the parent directory (..).
|
||||
|
||||
|
|
|
@ -29,9 +29,9 @@
|
|||
#cmakedefine01 DEBUG_MMS_SERVER
|
||||
#cmakedefine01 DEBUG_GOOSE_SUBSCRIBER
|
||||
#cmakedefine01 DEBUG_GOOSE_PUBLISHER
|
||||
#cmakedefine01 DEBUG_SV_SUBSCRIBER 0
|
||||
#cmakedefine01 DEBUG_SV_PUBLISHER 0
|
||||
#cmakedefine01 DEBUG_HAL_ETHERNET 0
|
||||
#cmakedefine01 DEBUG_SV_SUBSCRIBER
|
||||
#cmakedefine01 DEBUG_SV_PUBLISHER
|
||||
#cmakedefine01 DEBUG_HAL_ETHERNET
|
||||
|
||||
/* 1 ==> server runs in single threaded mode (one dedicated thread for the server)
|
||||
* 0 ==> server runs in multi threaded mode (one thread for each connection and
|
||||
|
|
|
@ -11,35 +11,34 @@ add_subdirectory(server_example_61400_25)
|
|||
add_subdirectory(server_example_setting_groups)
|
||||
add_subdirectory(server_example_logging)
|
||||
add_subdirectory(server_example_files)
|
||||
|
||||
add_subdirectory(iec61850_client_example1)
|
||||
add_subdirectory(iec61850_client_example2)
|
||||
add_subdirectory(iec61850_client_example3)
|
||||
add_subdirectory(iec61850_client_example4)
|
||||
add_subdirectory(iec61850_client_example5)
|
||||
IF(WIN32)
|
||||
else()
|
||||
add_subdirectory(iec61850_client_example_files)
|
||||
endif()
|
||||
add_subdirectory(iec61850_client_example_reporting)
|
||||
add_subdirectory(iec61850_client_example_log)
|
||||
|
||||
IF(WIN32)
|
||||
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../third_party/winpcap/Lib/wpcap.lib")
|
||||
message("Found winpcap -> compile examples for GOOSE and SV")
|
||||
add_subdirectory(server_example_goose)
|
||||
add_subdirectory(goose_subscriber)
|
||||
add_subdirectory(goose_publisher)
|
||||
add_subdirectory(sv_subscriber)
|
||||
add_subdirectory(iec61850_9_2_LE_example)
|
||||
add_subdirectory(iec61850_sv_client_example)
|
||||
add_subdirectory(sv_publisher)
|
||||
if(NOT WIN32)
|
||||
add_subdirectory(iec61850_client_example_files)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../third_party/winpcap/Lib/wpcap.lib")
|
||||
set(BUILD_SV_GOOSE_EXAMPLES ON)
|
||||
message("Found winpcap -> compile examples for GOOSE and SV")
|
||||
endif()
|
||||
else()
|
||||
add_subdirectory(server_example_goose)
|
||||
add_subdirectory(goose_subscriber)
|
||||
add_subdirectory(goose_publisher)
|
||||
add_subdirectory(sv_subscriber)
|
||||
add_subdirectory(iec61850_9_2_LE_example)
|
||||
add_subdirectory(iec61850_sv_client_example)
|
||||
add_subdirectory(sv_publisher)
|
||||
set(BUILD_SV_GOOSE_EXAMPLES ON)
|
||||
endif()
|
||||
|
||||
if(${BUILD_SV_GOOSE_EXAMPLES})
|
||||
add_subdirectory(server_example_goose)
|
||||
add_subdirectory(goose_subscriber)
|
||||
add_subdirectory(goose_publisher)
|
||||
add_subdirectory(sv_subscriber)
|
||||
add_subdirectory(iec61850_9_2_LE_example)
|
||||
add_subdirectory(iec61850_sv_client_example)
|
||||
add_subdirectory(sv_publisher)
|
||||
endif()
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
#include "goose_receiver.h"
|
||||
#include "goose_subscriber.h"
|
||||
#include "hal_thread.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
|
|
@ -248,6 +248,8 @@ main(int argc, char** argv)
|
|||
case FileOperationType_Set:
|
||||
setFile(con);
|
||||
break;
|
||||
case FileOperationType_None:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ printJournalEntries(LinkedList journalEntries)
|
|||
}
|
||||
}
|
||||
|
||||
void*
|
||||
void
|
||||
printRawMmsMessage(void* parameter, uint8_t* message, int messageLength, bool received)
|
||||
{
|
||||
if (received)
|
||||
|
|
|
@ -1,23 +1,40 @@
|
|||
FIND_PACKAGE(SWIG REQUIRED)
|
||||
INCLUDE(${SWIG_USE_FILE})
|
||||
FIND_PACKAGE(PythonLibs REQUIRED)
|
||||
FIND_PACKAGE ( PythonInterp ${PYTHONLIBS_VERSION_STRING} EXACT REQUIRED )
|
||||
INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH})
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
SET(CMAKE_SWIG_FLAGS "")
|
||||
SET_PROPERTY(SOURCE iec61850.i PROPERTY CPLUSPLUS ON)
|
||||
SWIG_ADD_MODULE(iec61850 python iec61850.i)
|
||||
IF(WIN32)
|
||||
SWIG_LINK_LIBRARIES(iec61850 ${PYTHON_LIBRARIES} iec61850 ws2_32)
|
||||
ELSE()
|
||||
SWIG_LINK_LIBRARIES(iec61850 ${PYTHON_LIBRARIES} iec61850-shared)
|
||||
ENDIF(WIN32)
|
||||
EXECUTE_PROCESS ( #Finding python modules install path
|
||||
COMMAND ${PYTHON_EXECUTABLE} -c
|
||||
"import site, sys; sys.stdout.write(site.getsitepackages()[-1])"
|
||||
OUTPUT_VARIABLE PYTHON_SITE_DIR
|
||||
)
|
||||
INSTALL ( FILES ${CMAKE_CURRENT_BINARY_DIR}/iec61850.py DESTINATION ${PYTHON_SITE_DIR})
|
||||
INSTALL ( TARGETS _iec61850 LIBRARY DESTINATION ${PYTHON_SITE_DIR})
|
||||
find_package(SWIG REQUIRED)
|
||||
include(${SWIG_USE_FILE})
|
||||
|
||||
find_package(PythonLibs REQUIRED)
|
||||
find_package(PythonInterp ${PYTHONLIBS_VERSION_STRING} EXACT REQUIRED)
|
||||
|
||||
include_directories(${PYTHON_INCLUDE_PATH})
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
set(CMAKE_SWIG_FLAGS "")
|
||||
set_property(SOURCE iec61850.i PROPERTY CPLUSPLUS ON)
|
||||
|
||||
if(WIN32)
|
||||
set(LIBS iec61850 ws2_32)
|
||||
else()
|
||||
set(LIBS iec61850-shared)
|
||||
endif()
|
||||
|
||||
if(${SWIG_VERSION} VERSION_LESS 3.0)
|
||||
swig_add_module(iec61850 python iec61850.i)
|
||||
else()
|
||||
swig_add_library(iec61850
|
||||
LANGUAGE python
|
||||
SOURCES iec61850.i
|
||||
)
|
||||
endif()
|
||||
|
||||
swig_link_libraries(iec61850 ${PYTHON_LIBRARIES} ${LIBS})
|
||||
|
||||
# Finding python modules install path
|
||||
execute_process(
|
||||
COMMAND ${PYTHON_EXECUTABLE} -c
|
||||
"import site, sys; sys.stdout.write(site.getsitepackages()[-1])"
|
||||
OUTPUT_VARIABLE PYTHON_SITE_DIR
|
||||
)
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/iec61850.py DESTINATION ${PYTHON_SITE_DIR})
|
||||
install(TARGETS _iec61850 LIBRARY DESTINATION ${PYTHON_SITE_DIR})
|
||||
|
||||
add_test(test_pyiec61850 ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/test_pyiec61850.py)
|
||||
|
|
|
@ -811,3 +811,10 @@ GooseReceiver_tick(GooseReceiver self)
|
|||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
GooseReceiver_addHandleSet(GooseReceiver self, EthernetHandleSet handles)
|
||||
{
|
||||
return EthernetHandleSet_addSocket(handles, self->ethSocket);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,18 +24,19 @@
|
|||
#ifndef GOOSE_RECEIVER_H_
|
||||
#define GOOSE_RECEIVER_H_
|
||||
|
||||
#include <goose_subscriber.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
/**
|
||||
* \addtogroup goose_api_group
|
||||
*/
|
||||
/**@{*/
|
||||
|
||||
typedef struct sGooseSubscriber* GooseSubscriber;
|
||||
|
||||
typedef struct sGooseReceiver* GooseReceiver;
|
||||
|
||||
|
@ -133,6 +134,20 @@ GooseReceiver_stopThreadless(GooseReceiver self);
|
|||
bool
|
||||
GooseReceiver_tick(GooseReceiver self);
|
||||
|
||||
/* Forward declaration */
|
||||
typedef struct sEthernetHandleSet* EthernetHandleSet;
|
||||
|
||||
/**
|
||||
* \brief Add the receiver to a handleset for multiplexed asynchronous IO.
|
||||
*
|
||||
* Note: This function must only be called after GooseReceiver_startThreadless().
|
||||
*
|
||||
* \param[in] self The SVReceiver instance.
|
||||
* \param[inout] handles The EthernetHandleSet to which the EthernetSocket of this receiver should be added.
|
||||
*/
|
||||
void
|
||||
GooseReceiver_addHandleSet(GooseReceiver self, EthernetHandleSet handles);
|
||||
|
||||
/**@}*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
*/
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/poll.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <net/if.h>
|
||||
|
@ -46,12 +47,82 @@ struct sEthernetSocket {
|
|||
struct bpf_program bpfProgram; // BPF filter machine code program.
|
||||
};
|
||||
|
||||
int _Ethernet_activateBpdFilter(EthernetSocket self)
|
||||
struct sEthernetHandleSet {
|
||||
struct pollfd *handles;
|
||||
int nhandles;
|
||||
};
|
||||
|
||||
EthernetHandleSet
|
||||
EthernetHandleSet_new(void)
|
||||
{
|
||||
EthernetHandleSet result = (EthernetHandleSet) GLOBAL_MALLOC(sizeof(struct sEthernetHandleSet));
|
||||
|
||||
if (result != NULL) {
|
||||
result->handles = NULL;
|
||||
result->nhandles = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetHandleSet_addSocket(EthernetHandleSet self, const EthernetSocket sock)
|
||||
{
|
||||
if (self != NULL && sock != NULL) {
|
||||
int i = self->nhandles++;
|
||||
self->handles = realloc(self->handles, self->nhandles * sizeof(struct pollfd));
|
||||
|
||||
self->handles[i].fd = sock->bpf;
|
||||
self->handles[i].events = POLLIN;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EthernetHandleSet_removeSocket(EthernetHandleSet self, const EthernetSocket sock)
|
||||
{
|
||||
if ((self != NULL) && (sock != NULL)) {
|
||||
unsigned i;
|
||||
for (i = 0; i < self->nhandles; i++) {
|
||||
if (self->handles[i].fd == sock->bpf) {
|
||||
memmove(&self->handles[i], &self->handles[i+1], sizeof(struct pollfd) * (self->nhandles - i - 1));
|
||||
self->nhandles--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
EthernetHandleSet_waitReady(EthernetHandleSet self, unsigned int timeoutMs)
|
||||
{
|
||||
int result;
|
||||
|
||||
if ((self != NULL) && (self->nhandles >= 0)) {
|
||||
result = poll(self->handles, self->nhandles, timeoutMs);
|
||||
}
|
||||
else {
|
||||
result = -1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetHandleSet_destroy(EthernetHandleSet self)
|
||||
{
|
||||
if (self->nhandles)
|
||||
free(self->handles);
|
||||
|
||||
GLOBAL_FREEMEM(self);
|
||||
}
|
||||
int
|
||||
activateBpdFilter(EthernetSocket self)
|
||||
{
|
||||
return ioctl(self->bpf, BIOCSETF, &self->bpfProgram);
|
||||
}
|
||||
|
||||
int _Ethernet_setBpfEthernetAddressFilter(EthernetSocket self, uint8_t *addr)
|
||||
static int
|
||||
setBpfEthernetAddressFilter(EthernetSocket self, uint8_t *addr)
|
||||
{
|
||||
if (addr)
|
||||
{
|
||||
|
@ -62,18 +133,19 @@ int _Ethernet_setBpfEthernetAddressFilter(EthernetSocket self, uint8_t *addr)
|
|||
memcpy((void *)&self->bpfProgram.bf_insns[3].k, &addr[2], 4);
|
||||
memcpy((void *)&self->bpfProgram.bf_insns[5].k, &addr, 2);
|
||||
|
||||
return _Ethernet_activateBpdFilter(self);
|
||||
return activateBpdFilter(self);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Disable Ethernet address filter.
|
||||
self->bpfProgram.bf_insns[0].k = 0;
|
||||
|
||||
return _Ethernet_activateBpdFilter(self);
|
||||
return activateBpdFilter(self);
|
||||
}
|
||||
}
|
||||
|
||||
int _Ethernet_setBpfEthertypeFilter(EthernetSocket self, uint16_t etherType)
|
||||
static int
|
||||
setBpfEthertypeFilter(EthernetSocket self, uint16_t etherType)
|
||||
{
|
||||
if (etherType)
|
||||
{
|
||||
|
@ -83,14 +155,14 @@ int _Ethernet_setBpfEthertypeFilter(EthernetSocket self, uint16_t etherType)
|
|||
// Set protocol.
|
||||
self->bpfProgram.bf_insns[9].k = etherType;
|
||||
|
||||
return _Ethernet_activateBpdFilter(self);
|
||||
return activateBpdFilter(self);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Disable Ethertype filter.
|
||||
self->bpfProgram.bf_insns[6].k = 0;
|
||||
|
||||
return _Ethernet_activateBpdFilter(self);
|
||||
return activateBpdFilter(self);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -283,13 +355,15 @@ Ethernet_createSocket(const char* interfaceId, uint8_t* destAddress)
|
|||
return self;
|
||||
}
|
||||
|
||||
void Ethernet_setProtocolFilter(EthernetSocket self, uint16_t etherType)
|
||||
void
|
||||
Ethernet_setProtocolFilter(EthernetSocket self, uint16_t etherType)
|
||||
{
|
||||
if (!self || !self->bpfProgram.bf_insns || _Ethernet_setBpfEthertypeFilter(self, etherType))
|
||||
if (!self || !self->bpfProgram.bf_insns || setBpfEthertypeFilter(self, etherType))
|
||||
printf("Unable to set ethertype filter!\n");
|
||||
}
|
||||
|
||||
int Ethernet_receivePacket(EthernetSocket self, uint8_t* buffer, int bufferSize)
|
||||
int
|
||||
Ethernet_receivePacket(EthernetSocket self, uint8_t* buffer, int bufferSize)
|
||||
{
|
||||
// If the actual buffer is empty, make a read call to the BSP device in order to get new data.
|
||||
if (self->bpfEnd - self->bpfPositon < 4)
|
||||
|
@ -335,13 +409,15 @@ int Ethernet_receivePacket(EthernetSocket self, uint8_t* buffer, int bufferSize)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void Ethernet_sendPacket(EthernetSocket self, uint8_t* buffer, int packetSize)
|
||||
void
|
||||
Ethernet_sendPacket(EthernetSocket self, uint8_t* buffer, int packetSize)
|
||||
{
|
||||
// Just send the packet as it is.
|
||||
write(self->bpf, buffer, packetSize);
|
||||
}
|
||||
|
||||
void Ethernet_destroySocket(EthernetSocket self)
|
||||
void
|
||||
Ethernet_destroySocket(EthernetSocket self)
|
||||
{
|
||||
// Close the BPF device.
|
||||
close(self->bpf);
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/poll.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/if_arp.h>
|
||||
|
@ -40,6 +41,75 @@ struct sEthernetSocket {
|
|||
struct sockaddr_ll socketAddress;
|
||||
};
|
||||
|
||||
struct sEthernetHandleSet {
|
||||
struct pollfd *handles;
|
||||
int nhandles;
|
||||
};
|
||||
|
||||
EthernetHandleSet
|
||||
EthernetHandleSet_new(void)
|
||||
{
|
||||
EthernetHandleSet result = (EthernetHandleSet) GLOBAL_MALLOC(sizeof(struct sEthernetHandleSet));
|
||||
|
||||
if (result != NULL) {
|
||||
result->handles = NULL;
|
||||
result->nhandles = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetHandleSet_addSocket(EthernetHandleSet self, const EthernetSocket sock)
|
||||
{
|
||||
if (self != NULL && sock != NULL) {
|
||||
int i = self->nhandles++;
|
||||
self->handles = realloc(self->handles, self->nhandles * sizeof(struct pollfd));
|
||||
|
||||
self->handles[i].fd = sock->rawSocket;
|
||||
self->handles[i].events = POLLIN;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EthernetHandleSet_removeSocket(EthernetHandleSet self, const EthernetSocket sock)
|
||||
{
|
||||
if ((self != NULL) && (sock != NULL)) {
|
||||
unsigned i;
|
||||
for (i = 0; i < self->nhandles; i++) {
|
||||
if (self->handles[i].fd == sock->rawSocket) {
|
||||
memmove(&self->handles[i], &self->handles[i+1], sizeof(struct pollfd) * (self->nhandles - i - 1));
|
||||
self->nhandles--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
EthernetHandleSet_waitReady(EthernetHandleSet self, unsigned int timeoutMs)
|
||||
{
|
||||
int result;
|
||||
|
||||
if ((self != NULL) && (self->nhandles >= 0)) {
|
||||
result = poll(self->handles, self->nhandles, timeoutMs);
|
||||
}
|
||||
else {
|
||||
result = -1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetHandleSet_destroy(EthernetHandleSet self)
|
||||
{
|
||||
if (self->nhandles)
|
||||
free(self->handles);
|
||||
|
||||
GLOBAL_FREEMEM(self);
|
||||
}
|
||||
|
||||
static int
|
||||
getInterfaceIndex(int sock, const char* deviceName)
|
||||
{
|
||||
|
|
|
@ -47,6 +47,8 @@
|
|||
|
||||
#define HAVE_REMOTE
|
||||
|
||||
// Enable WinPcap specific extension: pcap_getevent()
|
||||
#define WPCAP
|
||||
#include "pcap.h"
|
||||
|
||||
struct sEthernetSocket {
|
||||
|
@ -54,6 +56,11 @@ struct sEthernetSocket {
|
|||
struct bpf_program etherTypeFilter;
|
||||
};
|
||||
|
||||
struct sEthernetHandleSet {
|
||||
HANDLE *handles;
|
||||
int nhandles;
|
||||
};
|
||||
|
||||
#ifdef __GNUC__ /* detect MINGW */
|
||||
|
||||
#ifndef __MINGW64_VERSION_MAJOR
|
||||
|
@ -90,7 +97,6 @@ typedef ULONG (WINAPI* pgetadaptersaddresses)(ULONG family, ULONG flags, PVOID r
|
|||
|
||||
static pgetadaptersaddresses GetAdaptersAddresses;
|
||||
|
||||
|
||||
static bool dllLoaded = false;
|
||||
|
||||
static void
|
||||
|
@ -115,6 +121,71 @@ loadDLLs(void)
|
|||
|
||||
#endif /* __GNUC__ */
|
||||
|
||||
EthernetHandleSet
|
||||
EthernetHandleSet_new(void)
|
||||
{
|
||||
EthernetHandleSet result = (EthernetHandleSet) GLOBAL_MALLOC(sizeof(struct sEthernetHandleSet));
|
||||
|
||||
if (result != NULL) {
|
||||
result->handles = NULL;
|
||||
result->nhandles = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetHandleSet_addSocket(EthernetHandleSet self, const EthernetSocket sock)
|
||||
{
|
||||
if (self != NULL && sock != NULL) {
|
||||
int i = self->nhandles++;
|
||||
self->handles = (HANDLE *) realloc(self->handles, self->nhandles * sizeof(HANDLE));
|
||||
|
||||
self->handles[i] = pcap_getevent(sock->rawSocket);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EthernetHandleSet_removeSocket(EthernetHandleSet self, const EthernetSocket sock)
|
||||
{
|
||||
if ((self != NULL) && (sock != NULL)) {
|
||||
HANDLE h = pcap_getevent(socket->rawSocket);
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < self->nhandles; i++) {
|
||||
if (self->handles[i] == h) {
|
||||
memmove(&self->handles[i], &self->handles[i+1], sizeof(HANDLE) * (self->nhandles - i - 1));
|
||||
self->nhandles--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
EthernetHandleSet_waitReady(EthernetHandleSet self, unsigned int timeoutMs)
|
||||
{
|
||||
int result;
|
||||
|
||||
if ((self != NULL) && (self->nhandles > 0)) {
|
||||
result = WaitForMultipleObjects(self->nhandles, self->handles, 0, timeoutMs);
|
||||
}
|
||||
else {
|
||||
result = -1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetHandleSet_destroy(EthernetHandleSet self)
|
||||
{
|
||||
if (self->handles)
|
||||
free(self->handles);
|
||||
|
||||
GLOBAL_FREEMEM(self);
|
||||
}
|
||||
|
||||
static char*
|
||||
getInterfaceName(int interfaceIndex)
|
||||
{
|
||||
|
@ -215,8 +286,6 @@ getAdapterMacAddress(char* pcapAdapterName, uint8_t* macAddress)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
Ethernet_getInterfaceMACAddress(const char* interfaceId, uint8_t* addr)
|
||||
{
|
||||
|
@ -338,6 +407,28 @@ Ethernet_isSupported()
|
|||
return false;
|
||||
}
|
||||
|
||||
EthernetHandleSet
|
||||
EthernetHandleSet_new(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetHandleSet_addSocket(EthernetHandleSet self, const EthernetSocket sock)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
EthernetHandleSet_waitReady(EthernetHandleSet self, unsigned int timeoutMs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
EthernetHandleSet_destroy(EthernetHandleSet self)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Ethernet_getInterfaceMACAddress(const char* interfaceId, uint8_t* addr)
|
||||
{
|
||||
|
|
|
@ -48,6 +48,58 @@ extern "C" {
|
|||
*/
|
||||
typedef struct sEthernetSocket* EthernetSocket;
|
||||
|
||||
/** Opaque reference for a set of ethernet socket handles */
|
||||
typedef struct sEthernetHandleSet* EthernetHandleSet;
|
||||
|
||||
/**
|
||||
* \brief Create a new connection handle set (EthernetHandleSet)
|
||||
*
|
||||
* \return new EthernetHandleSet instance
|
||||
*/
|
||||
EthernetHandleSet
|
||||
EthernetHandleSet_new(void);
|
||||
|
||||
/**
|
||||
* \brief add a socket to an existing handle set
|
||||
*
|
||||
* \param self the HandleSet instance
|
||||
* \param sock the socket to add
|
||||
*/
|
||||
void
|
||||
EthernetHandleSet_addSocket(EthernetHandleSet self, const EthernetSocket sock);
|
||||
|
||||
/**
|
||||
* \brief remove a socket from an existing handle set
|
||||
*
|
||||
* \param self the HandleSet instance
|
||||
* \param sock the socket to add
|
||||
*/
|
||||
void
|
||||
EthernetHandleSet_removeSocket(EthernetHandleSet self, const EthernetSocket sock);
|
||||
|
||||
/**
|
||||
* \brief wait for a socket to become ready
|
||||
*
|
||||
* This function is corresponding to the BSD socket select function.
|
||||
* The function will return after \p timeoutMs ms if no data is pending.
|
||||
*
|
||||
* \param self the HandleSet instance
|
||||
* \param timeout in milliseconds (ms)
|
||||
* \return It returns the number of sockets on which data is pending
|
||||
* or 0 if no data is pending on any of the monitored connections.
|
||||
* The function shall return -1 if a socket error occures.
|
||||
*/
|
||||
int
|
||||
EthernetHandleSet_waitReady(EthernetHandleSet self, unsigned int timeoutMs);
|
||||
|
||||
/**
|
||||
* \brief destroy the EthernetHandleSet instance
|
||||
*
|
||||
* \param self the HandleSet instance to destroy
|
||||
*/
|
||||
void
|
||||
EthernetHandleSet_destroy(EthernetHandleSet self);
|
||||
|
||||
/**
|
||||
* \brief Return the MAC address of an Ethernet interface.
|
||||
*
|
||||
|
|
|
@ -63,7 +63,7 @@ HandleSet
|
|||
Handleset_new(void);
|
||||
|
||||
/**
|
||||
* \brief add a soecket to an existing handle set
|
||||
* \brief add a socket to an existing handle set
|
||||
*
|
||||
* \param self the HandleSet instance
|
||||
* \param sock the socket to add
|
||||
|
@ -71,18 +71,17 @@ Handleset_new(void);
|
|||
void
|
||||
Handleset_addSocket(HandleSet self, const Socket sock);
|
||||
|
||||
|
||||
/**
|
||||
* \brief wait for a socket to become ready
|
||||
*
|
||||
* This function is corresponding to the BSD socket select function.
|
||||
* It returns the number of sockets on which data is pending or 0 if no data is pending
|
||||
* on any of the monitored connections. The function will return after "timeout" ms if no
|
||||
* data is pending.
|
||||
* The function shall return -1 if a socket error occures.
|
||||
* The function will return after \p timeoutMs ms if no data is pending.
|
||||
*
|
||||
* \param self the HandleSet instance
|
||||
* \param timeout in milliseconds (ms)
|
||||
* \param self the HandleSet instance
|
||||
* \param timeout in milliseconds (ms)
|
||||
* \return It returns the number of sockets on which data is pending
|
||||
* or 0 if no data is pending on any of the monitored connections.
|
||||
* The function shall return -1 if a socket error occures.
|
||||
*/
|
||||
int
|
||||
Handleset_waitReady(HandleSet self, unsigned int timeoutMs);
|
||||
|
|
|
@ -351,7 +351,6 @@ IsoClientConnection_associate(IsoClientConnection self, IsoConnectionParameters
|
|||
goto returnError;
|
||||
}
|
||||
|
||||
|
||||
ByteBuffer_wrap(self->receivePayloadBuffer, self->acseConnection.userDataBuffer,
|
||||
self->acseConnection.userDataBufferSize, self->acseConnection.userDataBufferSize);
|
||||
|
||||
|
|
|
@ -449,6 +449,8 @@ CotpConnection_init(CotpConnection* self, Socket socket,
|
|||
self->options.tSelDst = tsel;
|
||||
self->payload = payloadBuffer;
|
||||
|
||||
CotpConnection_resetPayload(self);
|
||||
|
||||
/* default TPDU size is maximum size */
|
||||
CotpConnection_setTpduSize(self, COTP_MAX_TPDU_SIZE);
|
||||
|
||||
|
|
|
@ -35,45 +35,48 @@
|
|||
|
||||
void
|
||||
mmsClient_createDeleteNamedVariableListRequest(long invokeId, ByteBuffer* writeBuffer,
|
||||
const char* domainId, const char* listNameId)
|
||||
const char* domainId, const char* listNameId)
|
||||
{
|
||||
MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId);
|
||||
MmsPdu_t* mmsPdu = mmsClient_createConfirmedRequestPdu(invokeId);
|
||||
|
||||
mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.present =
|
||||
ConfirmedServiceRequest_PR_deleteNamedVariableList;
|
||||
mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.present =
|
||||
ConfirmedServiceRequest_PR_deleteNamedVariableList;
|
||||
|
||||
DeleteNamedVariableListRequest_t* request =
|
||||
&(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.deleteNamedVariableList);
|
||||
DeleteNamedVariableListRequest_t* request =
|
||||
&(mmsPdu->choice.confirmedRequestPdu.confirmedServiceRequest.choice.deleteNamedVariableList);
|
||||
|
||||
request->listOfVariableListName = (struct DeleteNamedVariableListRequest__listOfVariableListName*) GLOBAL_CALLOC(1,
|
||||
sizeof(struct DeleteNamedVariableListRequest__listOfVariableListName));
|
||||
request->listOfVariableListName = (struct DeleteNamedVariableListRequest__listOfVariableListName*) GLOBAL_CALLOC(1,
|
||||
sizeof(struct DeleteNamedVariableListRequest__listOfVariableListName));
|
||||
|
||||
request->listOfVariableListName->list.count = 1;
|
||||
request->listOfVariableListName->list.size = 1;
|
||||
request->listOfVariableListName->list.count = 1;
|
||||
request->listOfVariableListName->list.size = 1;
|
||||
|
||||
request->listOfVariableListName->list.array = (ObjectName_t**) GLOBAL_CALLOC(1, sizeof(ObjectName_t*));
|
||||
request->listOfVariableListName->list.array[0] = (ObjectName_t*) GLOBAL_CALLOC(1, sizeof(ObjectName_t));
|
||||
request->listOfVariableListName->list.array = (ObjectName_t**) GLOBAL_CALLOC(1, sizeof(ObjectName_t*));
|
||||
request->listOfVariableListName->list.array[0] = (ObjectName_t*) GLOBAL_CALLOC(1, sizeof(ObjectName_t));
|
||||
|
||||
if (domainId != NULL) {
|
||||
if (domainId != NULL) {
|
||||
request->listOfVariableListName->list.array[0]->present = ObjectName_PR_domainspecific;
|
||||
request->listOfVariableListName->list.array[0]->choice.domainspecific.domainId.size = strlen(domainId);
|
||||
request->listOfVariableListName->list.array[0]->choice.domainspecific.domainId.buf = (uint8_t*) StringUtils_copyString(domainId);
|
||||
request->listOfVariableListName->list.array[0]->choice.domainspecific.domainId.buf =
|
||||
(uint8_t*) StringUtils_copyString(domainId);
|
||||
request->listOfVariableListName->list.array[0]->choice.domainspecific.itemId.size = strlen(listNameId);
|
||||
request->listOfVariableListName->list.array[0]->choice.domainspecific.itemId.buf = (uint8_t*) StringUtils_copyString(listNameId);
|
||||
}
|
||||
else {
|
||||
request->listOfVariableListName->list.array[0]->present = ObjectName_PR_vmdspecific;
|
||||
request->listOfVariableListName->list.array[0]->choice.vmdspecific.size = strlen(listNameId);
|
||||
request->listOfVariableListName->list.array[0]->choice.vmdspecific.buf = (uint8_t*) StringUtils_copyString(listNameId);
|
||||
}
|
||||
request->listOfVariableListName->list.array[0]->choice.domainspecific.itemId.buf =
|
||||
(uint8_t*) StringUtils_copyString(listNameId);
|
||||
}
|
||||
else {
|
||||
request->listOfVariableListName->list.array[0]->present = ObjectName_PR_vmdspecific;
|
||||
request->listOfVariableListName->list.array[0]->choice.vmdspecific.size = strlen(listNameId);
|
||||
request->listOfVariableListName->list.array[0]->choice.vmdspecific.buf =
|
||||
(uint8_t*) StringUtils_copyString(listNameId);
|
||||
}
|
||||
|
||||
request->scopeOfDelete = (INTEGER_t*) GLOBAL_CALLOC(1, sizeof(INTEGER_t));
|
||||
asn_long2INTEGER(request->scopeOfDelete, DeleteNamedVariableListRequest__scopeOfDelete_specific);
|
||||
request->scopeOfDelete = (INTEGER_t*) GLOBAL_CALLOC(1, sizeof(INTEGER_t));
|
||||
asn_long2INTEGER(request->scopeOfDelete, DeleteNamedVariableListRequest__scopeOfDelete_specific);
|
||||
|
||||
der_encode(&asn_DEF_MmsPdu, mmsPdu,
|
||||
(asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer);
|
||||
(asn_app_consume_bytes_f*) mmsClient_write_out, (void*) writeBuffer);
|
||||
|
||||
asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0);
|
||||
asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -220,11 +223,25 @@ parseNamedVariableAttributes(GetNamedVariableListAttributesResponse_t* response,
|
|||
LinkedList attributes = LinkedList_create();
|
||||
|
||||
for (i = 0; i < attributesCount; i++) {
|
||||
char* domainId = mmsMsg_createStringFromAsnIdentifier(response->listOfVariable.list.array[i]->
|
||||
|
||||
char* domainId;
|
||||
char* itemId;
|
||||
|
||||
|
||||
if (response->listOfVariable.list.array[i]->variableSpecification.choice.name.present == ObjectName_PR_vmdspecific) {
|
||||
|
||||
domainId = NULL;
|
||||
|
||||
itemId = mmsMsg_createStringFromAsnIdentifier(response->listOfVariable.list.array[i]->
|
||||
variableSpecification.choice.name.choice.vmdspecific);
|
||||
}
|
||||
else {
|
||||
domainId = mmsMsg_createStringFromAsnIdentifier(response->listOfVariable.list.array[i]->
|
||||
variableSpecification.choice.name.choice.domainspecific.domainId);
|
||||
|
||||
char* itemId = mmsMsg_createStringFromAsnIdentifier(response->listOfVariable.list.array[i]->
|
||||
itemId = mmsMsg_createStringFromAsnIdentifier(response->listOfVariable.list.array[i]->
|
||||
variableSpecification.choice.name.choice.domainspecific.itemId);
|
||||
}
|
||||
|
||||
MmsVariableAccessSpecification* listEntry = MmsVariableAccessSpecification_create(domainId, itemId);
|
||||
|
||||
|
|
|
@ -498,8 +498,7 @@ mmsServer_handleDefineNamedVariableListRequest(
|
|||
char variableListName[65];
|
||||
|
||||
if (request->variableListName.choice.aaspecific.size > 64) {
|
||||
//TODO send reject PDU instead?
|
||||
mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT);
|
||||
mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response);
|
||||
goto exit_free_struct;
|
||||
}
|
||||
|
||||
|
@ -543,8 +542,7 @@ mmsServer_handleDefineNamedVariableListRequest(
|
|||
char variableListName[65];
|
||||
|
||||
if (request->variableListName.choice.vmdspecific.size > 64) {
|
||||
//TODO send reject PDU instead?
|
||||
mmsMsg_createServiceErrorPdu(invokeId, response, MMS_ERROR_ACCESS_OBJECT_NON_EXISTENT);
|
||||
mmsMsg_createMmsRejectPdu(&invokeId, MMS_ERROR_REJECT_REQUEST_INVALID_ARGUMENT, response);
|
||||
goto exit_free_struct;
|
||||
}
|
||||
|
||||
|
@ -583,7 +581,6 @@ mmsServer_handleDefineNamedVariableListRequest(
|
|||
exit_free_struct:
|
||||
asn_DEF_MmsPdu.free_struct(&asn_DEF_MmsPdu, mmsPdu, 0);
|
||||
|
||||
exit_function:
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ struct sSV_ASDU {
|
|||
|
||||
uint64_t refrTm;
|
||||
uint8_t smpMod;
|
||||
uint16_t smpRate;
|
||||
|
||||
uint8_t* smpCntBuf;
|
||||
|
||||
|
@ -220,6 +221,34 @@ encodeInt32FixedSize(int32_t value, uint8_t* buffer, int bufPos)
|
|||
return bufPos;
|
||||
}
|
||||
|
||||
static int
|
||||
encodeInt64FixedSize(int64_t value, uint8_t* buffer, int bufPos)
|
||||
{
|
||||
uint8_t* valueArray = (uint8_t*) &value;
|
||||
|
||||
#if (ORDER_LITTLE_ENDIAN == 1)
|
||||
buffer[bufPos++] = valueArray[7];
|
||||
buffer[bufPos++] = valueArray[6];
|
||||
buffer[bufPos++] = valueArray[5];
|
||||
buffer[bufPos++] = valueArray[4];
|
||||
buffer[bufPos++] = valueArray[3];
|
||||
buffer[bufPos++] = valueArray[2];
|
||||
buffer[bufPos++] = valueArray[1];
|
||||
buffer[bufPos++] = valueArray[0];
|
||||
#else
|
||||
buffer[bufPos++] = valueArray[0];
|
||||
buffer[bufPos++] = valueArray[1];
|
||||
buffer[bufPos++] = valueArray[2];
|
||||
buffer[bufPos++] = valueArray[3];
|
||||
buffer[bufPos++] = valueArray[4];
|
||||
buffer[bufPos++] = valueArray[5];
|
||||
buffer[bufPos++] = valueArray[6];
|
||||
buffer[bufPos++] = valueArray[7];
|
||||
#endif
|
||||
|
||||
return bufPos;
|
||||
}
|
||||
|
||||
static int
|
||||
encodeUtcTime(uint64_t timeval, uint8_t* buffer, int bufPos)
|
||||
{
|
||||
|
@ -257,13 +286,13 @@ encodeUtcTime(uint64_t timeval, uint8_t* buffer, int bufPos)
|
|||
SampledValuesPublisher
|
||||
SampledValuesPublisher_create(CommParameters* parameters, const char* interfaceId)
|
||||
{
|
||||
SampledValuesPublisher self = (SampledValuesPublisher) GLOBAL_CALLOC(1, sizeof(struct sSampledValuesPublisher));
|
||||
SampledValuesPublisher self = (SampledValuesPublisher) GLOBAL_CALLOC(1, sizeof(struct sSampledValuesPublisher));
|
||||
|
||||
self->asduLIst = NULL;
|
||||
self->asduLIst = NULL;
|
||||
|
||||
preparePacketBuffer(self, parameters, interfaceId);
|
||||
preparePacketBuffer(self, parameters, interfaceId);
|
||||
|
||||
return self;
|
||||
return self;
|
||||
}
|
||||
|
||||
SV_ASDU
|
||||
|
@ -369,7 +398,8 @@ SV_ASDU_encodeToBuffer(SV_ASDU self, uint8_t* buffer, int bufPos)
|
|||
buffer[bufPos++] = self->smpSynch;
|
||||
|
||||
/* SmpRate */
|
||||
//TODO implement me
|
||||
bufPos = BerEncoder_encodeTL(0x86, 2, buffer, bufPos);
|
||||
bufPos = encodeUInt16FixedSize(self->smpRate, buffer, bufPos);
|
||||
|
||||
/* Sample */
|
||||
bufPos = BerEncoder_encodeTL(0x87, self->dataSize, buffer, bufPos);
|
||||
|
@ -377,15 +407,11 @@ SV_ASDU_encodeToBuffer(SV_ASDU self, uint8_t* buffer, int bufPos)
|
|||
self->_dataBuffer = buffer + bufPos;
|
||||
|
||||
bufPos += self->dataSize; /* data has to inserted by user before sending message */
|
||||
|
||||
|
||||
/* SmpMod */
|
||||
if (self->hasSmpMod) {
|
||||
bufPos = BerEncoder_encodeTL(0x84, 4, buffer, bufPos);
|
||||
buffer[bufPos++] = 0;
|
||||
buffer[bufPos++] = 0;
|
||||
buffer[bufPos++] = 0;
|
||||
buffer[bufPos++] = self->smpMod;
|
||||
|
||||
bufPos = BerEncoder_encodeTL(0x88, 4, buffer, bufPos);
|
||||
bufPos = encodeUInt16FixedSize(self->smpMod, buffer, bufPos);
|
||||
}
|
||||
|
||||
return bufPos;
|
||||
|
@ -465,7 +491,7 @@ SampledValuesPublisher_publish(SampledValuesPublisher self)
|
|||
void
|
||||
SampledValuesPublisher_destroy(SampledValuesPublisher self)
|
||||
{
|
||||
GLOBAL_FREEMEM(self->buffer);
|
||||
GLOBAL_FREEMEM(self->buffer);
|
||||
}
|
||||
|
||||
|
||||
|
@ -508,6 +534,22 @@ SV_ASDU_setINT32(SV_ASDU self, int index, int32_t value)
|
|||
encodeInt32FixedSize(value, self->_dataBuffer, index);
|
||||
}
|
||||
|
||||
int
|
||||
SV_ASDU_addINT64(SV_ASDU self)
|
||||
{
|
||||
int index = self->dataSize;
|
||||
|
||||
self->dataSize += 8;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
void
|
||||
SV_ASDU_setINT64(SV_ASDU self, int index, int64_t value)
|
||||
{
|
||||
encodeInt64FixedSize(value, self->_dataBuffer, index);
|
||||
}
|
||||
|
||||
int
|
||||
SV_ASDU_addFLOAT(SV_ASDU self)
|
||||
{
|
||||
|
@ -523,7 +565,6 @@ SV_ASDU_setFLOAT(SV_ASDU self, int index, float value)
|
|||
{
|
||||
uint8_t* buf = (uint8_t*) &value;
|
||||
|
||||
|
||||
#if (ORDER_LITTLE_ENDIAN == 1)
|
||||
BerEncoder_revertByteOrder(buf, 4);
|
||||
#endif
|
||||
|
@ -550,11 +591,15 @@ void
|
|||
SV_ASDU_setFLOAT64(SV_ASDU self, int index, double value)
|
||||
{
|
||||
uint8_t* buf = (uint8_t*) &value;
|
||||
|
||||
#if (ORDER_LITTLE_ENDIAN == 1)
|
||||
BerEncoder_revertByteOrder(buf, 8);
|
||||
#endif
|
||||
|
||||
int i;
|
||||
|
||||
uint8_t* buffer = self->_dataBuffer + index;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
buffer[i] = buf[i];
|
||||
}
|
||||
|
@ -596,3 +641,9 @@ SV_ASDU_setSmpMod(SV_ASDU self, uint8_t smpMod)
|
|||
self->smpMod = smpMod;
|
||||
}
|
||||
|
||||
void
|
||||
SV_ASDU_setSmpRate(SV_ASDU self, uint16_t smpRate)
|
||||
{
|
||||
self->hasSmpRate = true;
|
||||
self->smpRate = smpRate;
|
||||
}
|
||||
|
|
|
@ -85,6 +85,12 @@ SV_ASDU_addINT32(SV_ASDU self);
|
|||
void
|
||||
SV_ASDU_setINT32(SV_ASDU self, int index, int32_t value);
|
||||
|
||||
int
|
||||
SV_ASDU_addINT64(SV_ASDU self);
|
||||
|
||||
void
|
||||
SV_ASDU_setINT64(SV_ASDU self, int index, int64_t value);
|
||||
|
||||
int
|
||||
SV_ASDU_addFLOAT(SV_ASDU self);
|
||||
|
||||
|
@ -121,6 +127,18 @@ SV_ASDU_setRefrTm(SV_ASDU self, uint64_t refrTm);
|
|||
void
|
||||
SV_ASDU_setSmpMod(SV_ASDU self, uint8_t smpMod);
|
||||
|
||||
/**
|
||||
* \brief Set the sample rate of the ASDU.
|
||||
*
|
||||
* If not set the transmitted ASDU will not contain an smpRate value.
|
||||
*
|
||||
* \param self the SV_ASDU
|
||||
*
|
||||
* \param smpRate Amount of samples (default per nominal period, see SmpMod).
|
||||
*/
|
||||
void
|
||||
SV_ASDU_setSmpRate(SV_ASDU self, uint16_t smpRate);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -50,7 +50,13 @@ struct sSVReceiver {
|
|||
|
||||
uint8_t* buffer;
|
||||
EthernetSocket ethSocket;
|
||||
|
||||
LinkedList subscriberList;
|
||||
|
||||
#if (CONFIG_MMS_THREADLESS_STACK == 0)
|
||||
Semaphore subscriberListLock;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
struct sSVSubscriber {
|
||||
|
@ -88,6 +94,10 @@ SVReceiver_create(void)
|
|||
self->buffer = (uint8_t*) GLOBAL_MALLOC(ETH_BUFFER_LENGTH);
|
||||
|
||||
self->checkDestAddr = false;
|
||||
|
||||
#if (CONFIG_MMS_THREADLESS_STACK == 0)
|
||||
self->subscriberListLock = Semaphore_create(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
return self;
|
||||
|
@ -111,13 +121,29 @@ SVReceiver_disableDestAddrCheck(SVReceiver self)
|
|||
void
|
||||
SVReceiver_addSubscriber(SVReceiver self, SVSubscriber subscriber)
|
||||
{
|
||||
#if (CONFIG_MMS_THREADLESS_STACK == 0)
|
||||
Semaphore_wait(self->subscriberListLock);
|
||||
#endif
|
||||
|
||||
LinkedList_add(self->subscriberList, (void*) subscriber);
|
||||
|
||||
#if (CONFIG_MMS_THREADLESS_STACK == 0)
|
||||
Semaphore_post(self->subscriberListLock);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
SVReceiver_removeSubscriber(SVReceiver self, SVSubscriber subscriber)
|
||||
{
|
||||
#if (CONFIG_MMS_THREADLESS_STACK == 0)
|
||||
Semaphore_wait(self->subscriberListLock);
|
||||
#endif
|
||||
|
||||
LinkedList_remove(self->subscriberList, (void*) subscriber);
|
||||
|
||||
#if (CONFIG_MMS_THREADLESS_STACK == 0)
|
||||
Semaphore_post(self->subscriberListLock);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -174,6 +200,10 @@ SVReceiver_destroy(SVReceiver self)
|
|||
LinkedList_destroyDeep(self->subscriberList,
|
||||
(LinkedListValueDeleteFunction) SVSubscriber_destroy);
|
||||
|
||||
#if (CONFIG_MMS_THREADLESS_STACK == 0)
|
||||
Semaphore_destroy(self->subscriberListLock);
|
||||
#endif
|
||||
|
||||
GLOBAL_FREEMEM(self->buffer);
|
||||
GLOBAL_FREEMEM(self);
|
||||
}
|
||||
|
@ -199,6 +229,11 @@ SVReceiver_stopThreadless(SVReceiver self)
|
|||
self->running = false;
|
||||
}
|
||||
|
||||
void
|
||||
SVReceiver_addHandleSet(SVReceiver self, EthernetHandleSet handles)
|
||||
{
|
||||
return EthernetHandleSet_addSocket(handles, self->ethSocket);
|
||||
}
|
||||
|
||||
static void
|
||||
parseASDU(SVReceiver self, SVSubscriber subscriber, uint8_t* buffer, int length)
|
||||
|
@ -398,6 +433,11 @@ parseSVMessage(SVReceiver self, int numbytes)
|
|||
|
||||
|
||||
/* check if there is a matching subscriber */
|
||||
|
||||
#if (CONFIG_MMS_THREADLESS_STACK == 0)
|
||||
Semaphore_wait(self->subscriberListLock);
|
||||
#endif
|
||||
|
||||
LinkedList element = LinkedList_getNext(self->subscriberList);
|
||||
|
||||
SVSubscriber subscriber;
|
||||
|
@ -427,6 +467,10 @@ parseSVMessage(SVReceiver self, int numbytes)
|
|||
element = LinkedList_getNext(element);
|
||||
}
|
||||
|
||||
#if (CONFIG_MMS_THREADLESS_STACK == 0)
|
||||
Semaphore_post(self->subscriberListLock);
|
||||
#endif
|
||||
|
||||
|
||||
if (subscriberFound)
|
||||
parseSVPayload(self, subscriber, buffer + bufPos, apduLength);
|
||||
|
@ -598,6 +642,20 @@ SVClientASDU_getINT32(SVClientASDU self, int index)
|
|||
return retVal;
|
||||
}
|
||||
|
||||
int64_t
|
||||
SVClientASDU_getINT64(SVClientASDU self, int index)
|
||||
{
|
||||
int64_t retVal = *((int64_t*) (self->dataBuffer + index));
|
||||
|
||||
#if (ORDER_LITTLE_ENDIAN == 1)
|
||||
uint8_t* buf = (uint8_t*) (&retVal);
|
||||
|
||||
BerEncoder_revertByteOrder(buf, 8);
|
||||
#endif
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
SVClientASDU_getINT8U(SVClientASDU self, int index)
|
||||
{
|
||||
|
@ -634,6 +692,19 @@ SVClientASDU_getINT32U(SVClientASDU self, int index)
|
|||
return retVal;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
SVClientASDU_getINT64U(SVClientASDU self, int index)
|
||||
{
|
||||
uint64_t retVal = *((uint64_t*) (self->dataBuffer + index));
|
||||
|
||||
#if (ORDER_LITTLE_ENDIAN == 1)
|
||||
uint8_t* buf = (uint8_t*) (&retVal);
|
||||
|
||||
BerEncoder_revertByteOrder(buf, 8);
|
||||
#endif
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
float
|
||||
SVClientASDU_getFLOAT32(SVClientASDU self, int index)
|
||||
|
|
|
@ -52,24 +52,25 @@ extern "C" {
|
|||
*
|
||||
* | IEC 61850 type | required bytes |
|
||||
* | -------------- | -------------- |
|
||||
* | BOOLEAN | 1 byte |
|
||||
* | INT8 | 1 byte |
|
||||
* | INT16 | 2 byte |
|
||||
* | INT32 | 4 byte |
|
||||
* | INT64 | 8 byte |
|
||||
* | INT8U | 1 byte |
|
||||
* | INT16U | 2 byte |
|
||||
* | INT24U | 3 byte |
|
||||
* | INT32U | 4 byte |
|
||||
* | FLOAT32 | 4 byte |
|
||||
* | FLOAT64 | 8 byte |
|
||||
* | ENUMERATED | 4 byte |
|
||||
* | CODED ENUM | 4 byte |
|
||||
* | OCTET STRING | 20 byte |
|
||||
* | VISIBLE STRING | 35 byte |
|
||||
* | TimeStamp | 8 byte |
|
||||
* | EntryTime | 6 byte |
|
||||
* | BITSTRING | 4 byte |
|
||||
* | BOOLEAN | 1 byte |
|
||||
* | INT8 | 1 byte |
|
||||
* | INT16 | 2 byte |
|
||||
* | INT32 | 4 byte |
|
||||
* | INT64 | 8 byte |
|
||||
* | INT8U | 1 byte |
|
||||
* | INT16U | 2 byte |
|
||||
* | INT24U | 3 byte |
|
||||
* | INT32U | 4 byte |
|
||||
* | INT64U | 8 byte |
|
||||
* | FLOAT32 | 4 byte |
|
||||
* | FLOAT64 | 8 byte |
|
||||
* | ENUMERATED | 4 byte |
|
||||
* | CODED ENUM | 4 byte |
|
||||
* | OCTET STRING | 20 byte |
|
||||
* | VISIBLE STRING | 35 byte |
|
||||
* | TimeStamp | 8 byte |
|
||||
* | EntryTime | 6 byte |
|
||||
* | BITSTRING | 4 byte |
|
||||
*
|
||||
* The SV subscriber API can be used independent of the IEC 61850 client API. In order to access the SVCB via MMS you
|
||||
* have to use the IEC 61850 client API. Please see \ref ClientSVControlBlock object in section \ref IEC61850_CLIENT_SV.
|
||||
|
@ -209,9 +210,32 @@ SVReceiver_startThreadless(SVReceiver self);
|
|||
void
|
||||
SVReceiver_stopThreadless(SVReceiver self);
|
||||
|
||||
/**
|
||||
* \brief Parse SV messages if they are available.
|
||||
*
|
||||
* Call after reception of ethernet frame and periodically to to house keeping tasks
|
||||
*
|
||||
* \param self the receiver object
|
||||
*
|
||||
* \return true if a message was available and has been parsed, false otherwise
|
||||
*/
|
||||
bool
|
||||
SVReceiver_tick(SVReceiver self);
|
||||
|
||||
/* Forward declaration */
|
||||
typedef struct sEthernetHandleSet* EthernetHandleSet;
|
||||
|
||||
/**
|
||||
* \brief Add the receiver to a handleset for multiplexed asynchronous IO.
|
||||
*
|
||||
* Note: This function must only be called after SVReceiver_startThreadless().
|
||||
*
|
||||
* \param[in] self The SVReceiver instance.
|
||||
* \param[inout] handles The EthernetHandleSet to which the EthernetSocket of this receiver should be added.
|
||||
*/
|
||||
void
|
||||
SVReceiver_addHandleSet(SVReceiver self, EthernetHandleSet handles);
|
||||
|
||||
/*
|
||||
* Subscriber
|
||||
*/
|
||||
|
@ -321,6 +345,17 @@ SVClientASDU_getINT16(SVClientASDU self, int index);
|
|||
int32_t
|
||||
SVClientASDU_getINT32(SVClientASDU self, int index);
|
||||
|
||||
/**
|
||||
* \brief Get an INT64 data value in the data part of the ASDU
|
||||
*
|
||||
* \param self ASDU object instance
|
||||
* \param index the index (byte position of the start) of the data in the data part
|
||||
*
|
||||
* \return SV data
|
||||
*/
|
||||
int64_t
|
||||
SVClientASDU_getINT64(SVClientASDU self, int index);
|
||||
|
||||
/**
|
||||
* \brief Get an INT8U data value in the data part of the ASDU
|
||||
*
|
||||
|
@ -354,6 +389,17 @@ SVClientASDU_getINT16U(SVClientASDU self, int index);
|
|||
uint32_t
|
||||
SVClientASDU_getINT32U(SVClientASDU self, int index);
|
||||
|
||||
/**
|
||||
* \brief Get an INT64U data value in the data part of the ASDU
|
||||
*
|
||||
* \param self ASDU object instance
|
||||
* \param index the index (byte position of the start) of the data in the data part
|
||||
*
|
||||
* \return SV data
|
||||
*/
|
||||
uint64_t
|
||||
SVClientASDU_getINT64U(SVClientASDU self, int index);
|
||||
|
||||
/**
|
||||
* \brief Get an FLOAT32 data value in the data part of the ASDU
|
||||
*
|
||||
|
|
Loading…
Add table
Reference in a new issue