summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Frust <tobiasfrust@gmail.com>2016-07-11 15:15:32 +0200
committerGitHub <noreply@github.com>2016-07-11 15:15:32 +0200
commit8af3d595e2856f81a46a91d67e96f53cb3b25d0f (patch)
treebd2cb6e80b0db90713f9d24de09577125d6f3d85
parent13783f932576a285b08cf518a6b0d679aac3c897 (diff)
parent409e2fd20af5620066796e43410a92521376b2c1 (diff)
downloadods-8af3d595e2856f81a46a91d67e96f53cb3b25d0f.tar.gz
ods-8af3d595e2856f81a46a91d67e96f53cb3b25d0f.tar.bz2
ods-8af3d595e2856f81a46a91d67e96f53cb3b25d0f.tar.xz
ods-8af3d595e2856f81a46a91d67e96f53cb3b25d0f.zip
Merge pull request #1 from tobiasfrust/master
Implemented DetectorSimulator with basic functionalities
-rw-r--r--.gitignore3
-rw-r--r--src/CMakeLists.txt56
-rw-r--r--src/CMakeLists.txt~47
-rw-r--r--src/ConfigReader/ConfigReader.cpp25
-rw-r--r--src/ConfigReader/ConfigReader.h48
-rw-r--r--src/Detector/Detector.cpp26
-rw-r--r--src/Detector/Detector.h35
-rw-r--r--src/DetectorModule/DetectorModule.cpp109
-rw-r--r--src/DetectorModule/DetectorModule.h50
-rw-r--r--src/UDPClient/UDPClient.cpp142
-rw-r--r--src/UDPClient/UDPClient.h44
-rw-r--r--src/UDPServer/UDPServer.cpp198
-rw-r--r--src/UDPServer/UDPServer.h45
-rw-r--r--src/cmake/FindLibConfig.cmake73
-rw-r--r--src/main_client.cpp49
-rw-r--r--src/main_server.cpp66
16 files changed, 1016 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index 4581ef2..159a010 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,3 +27,6 @@
*.exe
*.out
*.app
+
+build/*
+
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..d77a039
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,56 @@
+cmake_minimum_required(VERSION 3.5)
+project(OnlineDetectorSimulator)
+
+#define some speciel output paths for libraries and executables
+set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
+set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
+
+#use c++11
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+set(Boost_USE_MULTITHREADED ON)
+SET(BOOST_MIN_VERSION "1.58.0")
+add_definitions(-DBOOST_LOG_DYN_LINK=1)
+
+#find required packages
+find_package(LibConfig REQUIRED)
+find_package(Boost ${BOOST_MIN_VERSION} REQUIRED COMPONENTS log filesystem)
+find_package(OpenMP)
+
+#add openmp
+if(OPENMP_FOUND)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
+endif()
+
+include_directories(
+ ${LIBCONFIGPP_INCLUDE_DIR}
+ ${BOOST_INCLUDE_DIRS}
+)
+
+set(LINK_LIBRARIES ${LINK_LIBRARIES}
+ ${LIBCONFIGPP_LIBRARY}
+ ${Boost_LIBRARIES}
+)
+
+set(SOURCES_CLIENT
+ "${CMAKE_SOURCE_DIR}/ConfigReader/ConfigReader.cpp"
+ "${CMAKE_SOURCE_DIR}/UDPClient/UDPClient.cpp"
+ "${CMAKE_SOURCE_DIR}/DetectorModule/DetectorModule.cpp"
+ "${CMAKE_SOURCE_DIR}/Detector/Detector.cpp"
+ "${CMAKE_SOURCE_DIR}/main_client.cpp"
+)
+
+set(SOURCES_SERVER
+ "${CMAKE_SOURCE_DIR}/UDPServer/UDPServer.cpp"
+ "${CMAKE_SOURCE_DIR}/main_server.cpp"
+)
+
+add_executable(onlineDetectorSimulatorServer ${SOURCES_SERVER})
+add_executable(onlineDetectorSimulatorClient ${SOURCES_CLIENT})
+target_link_libraries(onlineDetectorSimulatorClient ${LINK_LIBRARIES})
+target_link_libraries(onlineDetectorSimulatorServer ${LINK_LIBRARIES})
+
diff --git a/src/CMakeLists.txt~ b/src/CMakeLists.txt~
new file mode 100644
index 0000000..80196d9
--- /dev/null
+++ b/src/CMakeLists.txt~
@@ -0,0 +1,47 @@
+cmake_minimum_required(VERSION 3.5)
+project(OnlineDetectorSimulator)
+
+#define some speciel output paths for libraries and executables
+set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
+set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
+
+#use c++11
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+set(Boost_USE_MULTITHREADED ON)
+SET(BOOST_MIN_VERSION "1.58.0")
+add_definitions(-DBOOST_LOG_DYN_LINK=1)
+
+#find required packages
+find_package(LibConfig REQUIRED)
+find_package(Boost ${BOOST_MIN_VERSION} REQUIRED COMPONENTS log filesystem)
+find_package(OpenMP)
+
+#add openmp
+if(OPENMP_FOUND)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
+endif()
+
+include_directories(
+ ${LIBCONFIGPP_INCLUDE_DIR}
+ ${BOOST_INCLUDE_DIRS}
+)
+
+set(SOURCES_CLIENT
+ "${CMAKE_SOURCE_DIR}/UDPClient/UDPClient.cpp"
+ "${CMAKE_SOURCE_DIR}/main.cpp"
+)
+
+set(SOURCES_SERVER
+ "${CMAKE_SOURCE_DIR}/UDPServer/UDPServer.cpp"
+ "${CMAKE_SOURCE_DIR}/main_server.cpp"
+)
+
+add_executable(onlineDetectorSimulatorServer ${SOURCES_SERVER})
+add_executable(onlineDetectorSimulatorClient ${SOURCES_CLIENT})
+
+
diff --git a/src/ConfigReader/ConfigReader.cpp b/src/ConfigReader/ConfigReader.cpp
new file mode 100644
index 0000000..7589d6a
--- /dev/null
+++ b/src/ConfigReader/ConfigReader.cpp
@@ -0,0 +1,25 @@
+/*
+ * ConfigReader.cpp
+ *
+ * Created on: 18.04.2016
+ * Author: Tobias Frust (t.frust@hzdr.de)
+ */
+
+#include <iostream>
+#include <iomanip>
+#include <cstdlib>
+
+#include "ConfigReader.h"
+
+ConfigReader::ConfigReader(const char* configFile) {
+ try {
+ cfg.readFile(configFile);
+ } catch (const libconfig::FileIOException &fioex) {
+ std::cerr << "I/O error while reading file." << std::endl;
+ exit(1);
+ } catch (const libconfig::ParseException &pex) {
+ std::cerr << "Parse error at " << pex.getFile() << ":" << pex.getLine()
+ << " - " << pex.getError() << std::endl;
+ exit(1);
+ }
+}
diff --git a/src/ConfigReader/ConfigReader.h b/src/ConfigReader/ConfigReader.h
new file mode 100644
index 0000000..2819f41
--- /dev/null
+++ b/src/ConfigReader/ConfigReader.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2016 Tobias Frust
+ *
+ * ConfigReader.h
+ *
+ * Created on: 18.04.2016
+ * Author: Tobias Frust (t.frust@hzdr.de)
+ */
+
+#ifndef CONFIGREADER_H
+#define CONFIGREADER_H
+#pragma once
+
+#include <boost/log/trivial.hpp>
+
+#include <libconfig.h++>
+
+#include <string>
+
+class ConfigReader {
+public:
+ ConfigReader(const char* configFile);
+ ConfigReader(const ConfigReader& configReader) {
+ }
+
+ template<typename T>
+ bool lookupValue(const std::string& identifier, T& value) {
+ bool ret = cfg.lookupValue(identifier.c_str(), value);
+ BOOST_LOG_TRIVIAL(debug) << "Configuration value " << identifier << ": " << value;
+ return ret;
+ }
+
+ template<typename T>
+ bool lookupValue(const std::string& identifier, int index, T& value) {
+ libconfig::Setting& s = cfg.lookup(identifier.c_str());
+ if(s.getLength() > index){
+ value = s[index];
+ BOOST_LOG_TRIVIAL(debug) << "Configuration value " << identifier << "[" << index << "]: " << value;
+ return true;
+ }
+ return false;
+ }
+
+private:
+ libconfig::Config cfg;
+};
+
+#endif
diff --git a/src/Detector/Detector.cpp b/src/Detector/Detector.cpp
new file mode 100644
index 0000000..5dde6d1
--- /dev/null
+++ b/src/Detector/Detector.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2016 Tobias Frust
+ *
+ * Detector.cpp
+ *
+ * Created on: 30.06.2016
+ * Author: Tobias Frust
+ */
+
+
+#include "Detector.h"
+
+Detector::Detector(const std::string& address, const std::string& configPath, const unsigned int timeIntervall) :
+ timeIntervall_{timeIntervall},
+ numberOfDetectorModules_{27} {
+ modules_.reserve(numberOfDetectorModules_);
+ for(auto i = 0; i < numberOfDetectorModules_; i++){
+ modules_.emplace_back(i, address, configPath);
+ }
+}
+
+auto Detector::run() -> void {
+ for(auto i = 0; i < numberOfDetectorModules_; i++)
+ modules_[i].sendPeriodically(timeIntervall_);
+}
+
diff --git a/src/Detector/Detector.h b/src/Detector/Detector.h
new file mode 100644
index 0000000..1969dbd
--- /dev/null
+++ b/src/Detector/Detector.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 Tobias Frust
+ *
+ * Detector.h
+ *
+ * Created on: 30.06.2016
+ * Author: Tobias Frust
+ */
+
+#ifndef DETECTOR_H_
+#define DETECTOR_H_
+
+#include "../DetectorModule/DetectorModule.h"
+
+#include <vector>
+#include <thread>
+
+class Detector {
+public:
+ Detector(const std::string& address, const std::string& configPath, const unsigned int timeIntervall);
+
+ auto run() -> void;
+private:
+ std::vector<DetectorModule> modules_;
+
+ std::vector<std::thread> moduleThreads_;
+
+ unsigned int timeIntervall_;
+ int numberOfDetectorModules_;
+
+ auto readConfig(const std::string& configFile) -> bool;
+
+};
+
+#endif /* DETECTOR_H_ */
diff --git a/src/DetectorModule/DetectorModule.cpp b/src/DetectorModule/DetectorModule.cpp
new file mode 100644
index 0000000..bee50e9
--- /dev/null
+++ b/src/DetectorModule/DetectorModule.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2016 Tobias Frust
+ *
+ * DetectorModule.cpp
+ *
+ * Created on: 29.06.2016
+ * Author: Tobias Frust
+ */
+
+#include "DetectorModule.h"
+#include "../ConfigReader/ConfigReader.h"
+
+#include <boost/log/trivial.hpp>
+
+#include <exception>
+#include <fstream>
+
+void timer_start(std::function<void(void)> func, unsigned int interval){
+ std::thread([func, interval]() {
+ while (true)
+ {
+ func();
+ std::this_thread::sleep_for(std::chrono::microseconds(interval));
+ }
+ }).detach();
+}
+
+DetectorModule::DetectorModule(const int detectorID, const std::string& address, const std::string& configPath) :
+ detectorID_{detectorID},
+ numberOfDetectorsPerModule_{16},
+ index_{0},
+ client_{address, detectorID+4000} {
+
+ printf("Creating %d\n", detectorID);
+
+ if (readConfig(configPath)) {
+ throw std::runtime_error("DetectorModule: Configuration file could not be loaded successfully. Please check!");
+ }
+
+ sendBuffer_.resize(numberOfDetectorsPerModule_*numberOfProjections_*sizeof(unsigned short) + sizeof(std::size_t));
+
+ //read the input data from the file corresponding to the detectorModuleID
+ readInput();
+ printf("Created %d\n", detectorID);
+}
+
+auto DetectorModule::send() -> void{
+ BOOST_LOG_TRIVIAL(debug) << "Detectormodule " << detectorID_ << " :sending udp packet with index " << index_ << ".";
+// sendBuffer_[0] = (sizeof(std::size_t)) & 0xff;
+// sendBuffer_[1] = (sizeof(std::size_t) >> 8) & 0xff;
+// sendBuffer_[2] = (sizeof(std::size_t) >> 16) & 0xff;
+// sendBuffer_[3] = (sizeof(std::size_t) >> 24) & 0xff;
+// sendBuffer_[4] = (sizeof(std::size_t) >> 32) & 0xff;
+// sendBuffer_[5] = (sizeof(std::size_t) >> 40) & 0xff;
+// sendBuffer_[6] = (sizeof(std::size_t) >> 48) & 0xff;
+// sendBuffer_[7] = (sizeof(std::size_t) >> 56) & 0xff;
+ unsigned int bufferSizeIndex = index_ % 1000;
+ unsigned int sinoSize = numberOfDetectorsPerModule_*numberOfProjections_;
+ *reinterpret_cast<int*>(sendBuffer_.data()) = index_;
+ std::copy(((char*)buffer_.data())+sinoSize*bufferSizeIndex*sizeof(unsigned short), ((char*)buffer_.data())+(sinoSize*(1+bufferSizeIndex))*sizeof(unsigned short), sendBuffer_.begin()+sizeof(std::size_t));
+ client_.send(sendBuffer_.data(), sizeof(unsigned short)*numberOfDetectorsPerModule_*numberOfProjections_+sizeof(std::size_t));
+ ++index_;
+}
+
+auto DetectorModule::sendPeriodically(unsigned int timeIntervall) -> void {
+ std::function<void(void)> f = [=]() {
+ this->send();
+ };
+ timer_start(f, timeIntervall);
+}
+
+auto DetectorModule::readInput() -> void {
+ if(path_.back() != '/')
+ path_.append("/");
+ //open file
+ const std::string filePath = path_ + fileName_ + std::to_string(detectorID_+1) + fileEnding_;
+ BOOST_LOG_TRIVIAL(debug) << "DetectorModule: Path = " << filePath;
+ std::ifstream input(filePath, std::ios::in | std::ios::binary);
+ if(input){
+ //allocate memory in vector
+ std::streampos fileSize;
+ input.seekg(0, std::ios::end);
+ fileSize = input.tellg();
+ input.seekg(0, std::ios::beg);
+ buffer_.resize(fileSize / sizeof(unsigned short));
+ input.read((char*) &buffer_[0], fileSize);
+ }else{
+ throw std::runtime_error("File not found.");
+ }
+}
+
+auto DetectorModule::readConfig(const std::string& configFile) -> bool {
+ ConfigReader configReader = ConfigReader(configFile.data());
+ int samplingRate, scanRate;
+ if (configReader.lookupValue("numberOfFanDetectors", numberOfDetectors_)
+ && configReader.lookupValue("dataInputPath", path_)
+ && configReader.lookupValue("dataFileName", fileName_)
+ && configReader.lookupValue("dataFileEnding", fileEnding_)
+ && configReader.lookupValue("numberOfPlanes", numberOfPlanes_)
+ && configReader.lookupValue("samplingRate", samplingRate)
+ && configReader.lookupValue("scanRate", scanRate)
+ && configReader.lookupValue("numberOfDataFrames", numberOfFrames_)) {
+ numberOfProjections_ = samplingRate * 1000000 / scanRate;
+ return EXIT_SUCCESS;
+ }
+
+ return EXIT_FAILURE;
+}
+
diff --git a/src/DetectorModule/DetectorModule.h b/src/DetectorModule/DetectorModule.h
new file mode 100644
index 0000000..1bc36bb
--- /dev/null
+++ b/src/DetectorModule/DetectorModule.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2016 Tobias Frust
+ *
+ * DetectorModule.h
+ *
+ * Created on: 29.06.2016
+ * Author: Tobias Frust
+ */
+
+#ifndef DETECTORMODULE_H_
+#define DETECTORMODULE_H_
+
+#include "../UDPClient/UDPClient.h"
+
+#include <vector>
+
+#include <iostream>
+#include <chrono>
+#include <thread>
+#include <functional>
+
+class DetectorModule {
+public:
+ DetectorModule(const int detectorID, const std::string& address, const std::string& configPath);
+
+ auto sendPeriodically(unsigned int timeIntervall) -> void;
+
+private:
+ std::vector<unsigned short> buffer_;
+ std::vector<char> sendBuffer_;
+
+ int detectorID_;
+ UDPClient client_;
+
+ int numberOfDetectors_;
+ int numberOfPlanes_;
+ int numberOfProjections_;
+ int numberOfDetectorsPerModule_;
+ unsigned int numberOfFrames_;
+ std::string path_, fileName_, fileEnding_;
+
+ std::size_t index_;
+
+ auto readConfig(const std::string& configFile) -> bool;
+ auto readInput() -> void;
+ auto send() -> void;
+
+};
+
+#endif
diff --git a/src/UDPClient/UDPClient.cpp b/src/UDPClient/UDPClient.cpp
new file mode 100644
index 0000000..1d427ba
--- /dev/null
+++ b/src/UDPClient/UDPClient.cpp
@@ -0,0 +1,142 @@
+/*
+ * http://linux.m2osw.com/c-implementation-udp-clientserver
+ *
+ * UDPSender.cpp
+ *
+ * Created on: 29.06.2016
+ * Author: Tobias Frust
+ */
+
+ // ========================= CLIENT =========================
+
+ /** \brief Initialize a UDP client object.
+ *
+ * This function initializes the UDP client object using the address and the
+ * port as specified.
+ *
+ * The port is expected to be a host side port number (i.e. 59200).
+ *
+ * The \p addr parameter is a textual address. It may be an IPv4 or IPv6
+ * address and it can represent a host name or an address defined with
+ * just numbers. If the address cannot be resolved then an error occurs
+ * and constructor throws.
+ *
+ * \note
+ * The socket is open in this process. If you fork() or exec() then the
+ * socket will be closed by the operating system.
+ *
+ * \warning
+ * We only make use of the first address found by getaddrinfo(). All
+ * the other addresses are ignored.
+ *
+ * \exception udp_client_server_runtime_error
+ * The server could not be initialized properly. Either the address cannot be
+ * resolved, the port is incompatible or not available, or the socket could
+ * not be created.
+ *
+ * \param[in] addr The address to convert to a numeric IP.
+ * \param[in] port The port number.
+ */
+
+#include "UDPClient.h"
+
+#include <string.h>
+#include <unistd.h>
+
+#ifndef SOCK_CLOEXEC
+#define SOCK_CLOEXEC 0
+#endif
+
+ UDPClient::UDPClient(const std::string& addr, int port)
+ : f_port(port)
+ , f_addr(addr){
+ printf("Creating client %d\n", f_port);
+ char decimal_port[16];
+ snprintf(decimal_port, sizeof(decimal_port), "%d", f_port);
+ decimal_port[sizeof(decimal_port) / sizeof(decimal_port[0]) - 1] = '\0';
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ int r(getaddrinfo(addr.c_str(), decimal_port, &hints, &f_addrinfo));
+ if(r != 0 || f_addrinfo == NULL)
+ {
+ throw udp_client_server_runtime_error(("invalid address or port: \"" + addr + ":" + decimal_port + "\"").c_str());
+ }
+ f_socket = socket(f_addrinfo->ai_family, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
+ if(f_socket == -1)
+ {
+ freeaddrinfo(f_addrinfo);
+ throw udp_client_server_runtime_error(("could not create socket for: \"" + addr + ":" + decimal_port + "\"").c_str());
+ }
+ printf("Created client %d\n", f_port);
+ }
+
+ /** \brief Clean up the UDP client object.
+ *
+ * This function frees the address information structure and close the socket
+ * before returning.
+ */
+ UDPClient::~UDPClient()
+ {
+ freeaddrinfo(f_addrinfo);
+ close(f_socket);
+ }
+
+ /** \brief Retrieve a copy of the socket identifier.
+ *
+ * This function return the socket identifier as returned by the socket()
+ * function. This can be used to change some flags.
+ *
+ * \return The socket used by this UDP client.
+ */
+ int UDPClient::get_socket() const {
+ return f_socket;
+ }
+
+ /** \brief Retrieve the port used by this UDP client.
+ *
+ * This function returns the port used by this UDP client. The port is
+ * defined as an integer, host side.
+ *
+ * \return The port as expected in a host integer.
+ */
+ int UDPClient::get_port() const {
+ return f_port;
+ }
+
+ /** \brief Retrieve a copy of the address.
+ *
+ * This function returns a copy of the address as it was specified in the
+ * constructor. This does not return a canonalized version of the address.
+ *
+ * The address cannot be modified. If you need to send data on a different
+ * address, create a new UDP client.
+ *
+ * \return A string with a copy of the constructor input address.
+ */
+ std::string UDPClient::get_addr() const {
+ return f_addr;
+ }
+
+ /** \brief Send a message through this UDP client.
+ *
+ * This function sends \p msg through the UDP client socket. The function
+ * cannot be used to change the destination as it was defined when creating
+ * the udp_client object.
+ *
+ * The size must be small enough for the message to fit. In most cases we
+ * use these in Snap! to send very small signals (i.e. 4 bytes commands.)
+ * Any data we would want to share remains in the Cassandra database so
+ * that way we can avoid losing it because of a UDP message.
+ *
+ * \param[in] msg The message to send.
+ * \param[in] size The number of bytes representing this message.
+ *
+ * \return -1 if an error occurs, otherwise the number of bytes sent. errno
+ * is set accordingly on error.
+ */
+ int UDPClient::send(const char *msg, std::size_t size){
+ return sendto(f_socket, msg, size, 0, f_addrinfo->ai_addr, f_addrinfo->ai_addrlen);
+ }
diff --git a/src/UDPClient/UDPClient.h b/src/UDPClient/UDPClient.h
new file mode 100644
index 0000000..f6cf0d6
--- /dev/null
+++ b/src/UDPClient/UDPClient.h
@@ -0,0 +1,44 @@
+/*
+ * http://linux.m2osw.com/c-implementation-udp-clientserver
+ *
+ * UDPSender.h
+ *
+ * Created on: 29.06.2016
+ * Author: Tobias Frust
+ */
+
+#ifndef UDPCLIENT_H_
+#define UDPCLIENT_H_
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <stdexcept>
+#include <cstring>
+
+class udp_client_server_runtime_error : public std::runtime_error
+{
+public:
+ udp_client_server_runtime_error(const char *w) : std::runtime_error(w) {}
+};
+
+
+class UDPClient {
+public:
+ UDPClient(const std::string& addr, int port);
+ ~UDPClient();
+
+ int get_socket() const;
+ int get_port() const;
+ std::string get_addr() const;
+
+ int send(const char *msg, size_t size);
+
+private:
+ int f_socket;
+ int f_port;
+ std::string f_addr;
+ struct addrinfo * f_addrinfo;
+};
+
+#endif /* UDPCLIENT_H_ */
diff --git a/src/UDPServer/UDPServer.cpp b/src/UDPServer/UDPServer.cpp
new file mode 100644
index 0000000..3a50d0c
--- /dev/null
+++ b/src/UDPServer/UDPServer.cpp
@@ -0,0 +1,198 @@
+/*
+ * http://linux.m2osw.com/c-implementation-udp-clientserver
+ *
+ * UDPServer.cpp
+ *
+ * Created on: 29.06.2016
+ * Author: Tobias Frust
+ */
+
+// ========================= SEVER =========================
+
+/** \brief Initialize a UDP server object.
+ *
+ * This function initializes a UDP server object making it ready to
+ * receive messages.
+ *
+ * The server address and port are specified in the constructor so
+ * if you need to receive messages from several different addresses
+ * and/or port, you'll have to create a server for each.
+ *
+ * The address is a string and it can represent an IPv4 or IPv6
+ * address.
+ *
+ * Note that this function calls connect() to connect the socket
+ * to the specified address. To accept data on different UDP addresses
+ * and ports, multiple UDP servers must be created.
+ *
+ * \note
+ * The socket is open in this process. If you fork() or exec() then the
+ * socket will be closed by the operating system.
+ *
+ * \warning
+ * We only make use of the first address found by getaddrinfo(). All
+ * the other addresses are ignored.
+ *
+ * \exception udp_client_server_runtime_error
+ * The udp_client_server_runtime_error exception is raised when the address
+ * and port combinaison cannot be resolved or if the socket cannot be
+ * opened.
+ *
+ * \param[in] addr The address we receive on.
+ * \param[in] port The port we receive from.
+ */
+
+#include "UDPServer.h"
+
+#include <string.h>
+#include <unistd.h>
+
+#ifndef SOCK_CLOEXEC
+#define SOCK_CLOEXEC 0
+#endif
+
+UDPServer::UDPServer(const std::string& addr, int port)
+ : f_port(port)
+ , f_addr(addr)
+{
+ char decimal_port[16];
+ snprintf(decimal_port, sizeof(decimal_port), "%d", f_port);
+ decimal_port[sizeof(decimal_port) / sizeof(decimal_port[0]) - 1] = '\0';
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ int r(getaddrinfo(addr.c_str(), decimal_port, &hints, &f_addrinfo));
+ if(r != 0 || f_addrinfo == NULL)
+ {
+ throw udp_client_server_runtime_error(("invalid address or port for UDP socket: \"" + addr + ":" + decimal_port + "\"").c_str());
+ }
+ f_socket = socket(f_addrinfo->ai_family, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
+ if(f_socket == -1)
+ {
+ freeaddrinfo(f_addrinfo);
+ throw udp_client_server_runtime_error(("could not create UDP socket for: \"" + addr + ":" + decimal_port + "\"").c_str());
+ }
+ r = bind(f_socket, f_addrinfo->ai_addr, f_addrinfo->ai_addrlen);
+ if(r != 0)
+ {
+ freeaddrinfo(f_addrinfo);
+ close(f_socket);
+ throw udp_client_server_runtime_error(("could not bind UDP socket with: \"" + addr + ":" + decimal_port + "\"").c_str());
+ }
+}
+
+/** \brief Clean up the UDP server.
+ *
+ * This function frees the address info structures and close the socket.
+ */
+UDPServer::~UDPServer()
+{
+ freeaddrinfo(f_addrinfo);
+ close(f_socket);
+}
+
+/** \brief The socket used by this UDP server.
+ *
+ * This function returns the socket identifier. It can be useful if you are
+ * doing a select() on many sockets.
+ *
+ * \return The socket of this UDP server.
+ */
+int UDPServer::get_socket() const
+{
+ return f_socket;
+}
+
+/** \brief The port used by this UDP server.
+ *
+ * This function returns the port attached to the UDP server. It is a copy
+ * of the port specified in the constructor.
+ *
+ * \return The port of the UDP server.
+ */
+int UDPServer::get_port() const
+{
+ return f_port;
+}
+
+/** \brief Return the address of this UDP server.
+ *
+ * This function returns a verbatim copy of the address as passed to the
+ * constructor of the UDP server (i.e. it does not return the canonalized
+ * version of the address.)
+ *
+ * \return The address as passed to the constructor.
+ */
+std::string UDPServer::get_addr() const
+{
+ return f_addr;
+}
+
+/** \brief Wait on a message.
+ *
+ * This function waits until a message is received on this UDP server.
+ * There are no means to return from this function except by receiving
+ * a message. Remember that UDP does not have a connect state so whether
+ * another process quits does not change the status of this UDP server
+ * and thus it continues to wait forever.
+ *
+ * Note that you may change the type of socket by making it non-blocking
+ * (use the get_socket() to retrieve the socket identifier) in which
+ * case this function will not block if no message is available. Instead
+ * it returns immediately.
+ *
+ * \param[in] msg The buffer where the message is saved.
+ * \param[in] max_size The maximum size the message (i.e. size of the \p msg buffer.)
+ *
+ * \return The number of bytes read or -1 if an error occurs.
+ */
+int UDPServer::recv(char *msg, size_t max_size)
+{
+ return ::recv(f_socket, msg, max_size, 0);
+}
+
+/** \brief Wait for data to come in.
+ *
+ * This function waits for a given amount of time for data to come in. If
+ * no data comes in after max_wait_ms, the function returns with -1 and
+ * errno set to EAGAIN.
+ *
+ * The socket is expected to be a blocking socket (the default,) although
+ * it is possible to setup the socket as non-blocking if necessary for
+ * some other reason.
+ *
+ * This function blocks for a maximum amount of time as defined by
+ * max_wait_ms. It may return sooner with an error or a message.
+ *
+ * \param[in] msg The buffer where the message will be saved.
+ * \param[in] max_size The size of the \p msg buffer in bytes.
+ * \param[in] max_wait_ms The maximum number of milliseconds to wait for a message.
+ *
+ * \return -1 if an error occurs or the function timed out, the number of bytes received otherwise.
+ */
+int UDPServer::timed_recv(char *msg, size_t max_size, int max_wait_ms)
+{
+ fd_set s;
+ FD_ZERO(&s);
+ FD_SET(f_socket, &s);
+ struct timeval timeout;
+ timeout.tv_sec = max_wait_ms / 1000;
+ timeout.tv_usec = (max_wait_ms % 1000) * 1000;
+ int retval = select(f_socket + 1, &s, &s, &s, &timeout);
+ if(retval == -1)
+ {
+ // select() set errno accordingly
+ return -1;
+ }
+ if(retval > 0)
+ {
+ // our socket has data
+ return ::recv(f_socket, msg, max_size, 0);
+ }
+
+ // our socket has no data
+ errno = EAGAIN;
+ return -1;
+}
diff --git a/src/UDPServer/UDPServer.h b/src/UDPServer/UDPServer.h
new file mode 100644
index 0000000..22f33b3
--- /dev/null
+++ b/src/UDPServer/UDPServer.h
@@ -0,0 +1,45 @@
+/*
+ * http://linux.m2osw.com/c-implementation-udp-clientserver
+ *
+ * UDPServer.h
+ *
+ * Created on: 29.06.2016
+ * Author: Tobias Frust
+ */
+
+#ifndef UDPSERVER_H_
+#define UDPSERVER_H_
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <stdexcept>
+#include <cstring>
+
+class udp_client_server_runtime_error : public std::runtime_error
+{
+public:
+ udp_client_server_runtime_error(const char *w) : std::runtime_error(w) {}
+};
+
+class UDPServer
+{
+public:
+ UDPServer(const std::string& addr, int port);
+ ~UDPServer();
+
+ int get_socket() const;
+ int get_port() const;
+ std::string get_addr() const;
+
+ int recv(char *msg, size_t max_size);
+ int timed_recv(char *msg, size_t max_size, int max_wait_ms);
+
+private:
+ int f_socket;
+ int f_port;
+ std::string f_addr;
+ struct addrinfo * f_addrinfo;
+};
+
+#endif /* UDPSERVER_H_ */
diff --git a/src/cmake/FindLibConfig.cmake b/src/cmake/FindLibConfig.cmake
new file mode 100644
index 0000000..436d2a5
--- /dev/null
+++ b/src/cmake/FindLibConfig.cmake
@@ -0,0 +1,73 @@
+# Find the CUnit includes and library
+#
+# This module defines
+# LIBCONFIG_INCLUDE_DIR, where to find cppunit include files, etc.
+# LIBCONFIG_LIBRARIES, the libraries to link against to use CppUnit.
+# LIBCONFIG_STATIC_LIBRARIY_PATH
+# LIBCONFIG_FOUND, If false, do not try to use CppUnit.
+
+# also defined, but not for general use are
+# LIBCONFIG_LIBRARY, where to find the CUnit library.
+
+#MESSAGE("Searching for libconfig library")
+
+FIND_PATH(LIBCONFIG_INCLUDE_DIR libconfig.h
+ /usr/local/include
+ /usr/include
+)
+
+FIND_PATH(LIBCONFIGPP_INCLUDE_DIR libconfig.h++
+ /usr/local/include
+ /usr/include
+)
+
+FIND_LIBRARY(LIBCONFIG_LIBRARY config
+ /usr/local/lib
+ /usr/lib
+)
+
+FIND_LIBRARY(LIBCONFIGPP_LIBRARY config++
+ /usr/local/lib
+ /usr/lib
+)
+
+FIND_LIBRARY(LIBCONFIG_STATIC_LIBRARY "libconfig${CMAKE_STATIC_LIBRARY_SUFFIX}"
+ /usr/local/lib
+ /usr/lib
+)
+
+FIND_LIBRARY(LIBCONFIGPP_STATIC_LIBRARY "libconfig++${CMAKE_STATIC_LIBRARY_SUFFIX}"
+ /usr/local/lib
+ /usr/lib
+)
+
+
+IF(LIBCONFIG_INCLUDE_DIR)
+ IF(LIBCONFIG_LIBRARY)
+ SET(LIBCONFIG_FOUND TRUE)
+ SET(LIBCONFIG_LIBRARIES ${LIBCONFIG_LIBRARY})
+ SET(LIBCONFIG_STATIC_LIBRARY_PATH ${LIBCONFIG_STATIC_LIBRARY})
+ ENDIF(LIBCONFIG_LIBRARY)
+ENDIF(LIBCONFIG_INCLUDE_DIR)
+
+IF(LIBCONFIGPP_INCLUDE_DIR)
+ IF(LIBCONFIGPP_LIBRARY)
+ SET(LIBCONFIGPP_FOUND TRUE)
+ SET(LIBCONFIGPP_LIBRARIES ${LIBCONFIGPP_LIBRARY})
+ SET(LIBCONFIGPP_STATIC_LIBRARY_PATH ${LIBCONFIGPP_STATIC_LIBRARY})
+ ENDIF(LIBCONFIGPP_LIBRARY)
+ENDIF(LIBCONFIGPP_INCLUDE_DIR)
+
+IF (LIBCONFIG_FOUND)
+ IF (NOT LibConfig_FIND_QUIETLY)
+ MESSAGE(STATUS "Found LibConfig++: ${LIBCONFIGPP_LIBRARIES}" )
+ MESSAGE(STATUS "Found LibConfig: ${LIBCONFIG_LIBRARIES}")
+ MESSAGE(STATUS "static LibConfig path: ${LIBCONFIG_STATIC_LIBRARY_PATH}")
+ ENDIF (NOT LibConfig_FIND_QUIETLY)
+ELSE (LIBCONFIG_FOUND)
+ IF (LibConfig_FIND_REQUIRED)
+ MESSAGE(SEND_ERROR "Could NOT find LibConfig")
+ ENDIF (LibConfig_FIND_REQUIRED)
+ENDIF (LIBCONFIG_FOUND)
+
+MARK_AS_ADVANCED(LIBCONFIG_INCLUDE_DIR LIBCONFIG_LIBRARIES)
diff --git a/src/main_client.cpp b/src/main_client.cpp
new file mode 100644
index 0000000..2b9927d
--- /dev/null
+++ b/src/main_client.cpp
@@ -0,0 +1,49 @@
+#include "UDPClient/UDPClient.h"
+#include "DetectorModule/DetectorModule.h"
+#include "Detector/Detector.h"
+
+#include <boost/log/core.hpp>
+#include <boost/log/trivial.hpp>
+#include <boost/log/expressions.hpp>
+
+#include <iostream>
+#include <string>
+
+void initLog() {
+#ifndef NDEBUG
+ boost::log::core::get()->set_filter(boost::log::trivial::severity >= boost::log::trivial::debug);
+#else
+ boost::log::core::get()->set_filter(boost::log::trivial::severity >= boost::log::trivial::info);
+#endif
+}
+
+int main (int argc, char *argv[]){
+
+ if(argc < 2){
+ BOOST_LOG_TRIVIAL(error) << "Program usage: ./onlineDetectorSimulatorClient <images_per_second>!";
+ return 0;
+ }
+
+ int imagesPerSec = std::stoi(argv[1]);
+
+ double timegap = 1./(double)imagesPerSec;
+ unsigned int intervall = timegap*1000*1000;
+
+ initLog();
+
+ std::cout << "Sending UDP packages: " << std::endl;
+
+ auto configPath = std::string { "config.cfg" };
+ std::string address = "127.0.0.1";
+
+ Detector detector{address, configPath, intervall};
+
+ //DetectorModule detModule0 = DetectorModule(1, address, configPath);
+
+ detector.run();
+
+ std::cin.ignore();
+
+ return 0;
+
+}
diff --git a/src/main_server.cpp b/src/main_server.cpp
new file mode 100644
index 0000000..6e936e4
--- /dev/null
+++ b/src/main_server.cpp
@@ -0,0 +1,66 @@
+#include "UDPServer/UDPServer.h"
+
+#include <boost/log/core.hpp>
+#include <boost/log/trivial.hpp>
+#include <boost/log/expressions.hpp>
+
+#include <iostream>
+#include <string>
+#include <thread>
+
+void initLog() {
+#ifndef NDEBUG
+ boost::log::core::get()->set_filter(boost::log::trivial::severity >= boost::log::trivial::debug);
+#else
+ boost::log::core::get()->set_filter(boost::log::trivial::severity >= boost::log::trivial::info);
+#endif
+}
+
+void start(std::function<void(void)> func){
+ std::thread([func]() {
+ while (true)
+ {
+ func();
+ }
+ }).detach();
+}
+
+int main (int argc, char *argv[]){
+
+ initLog();
+
+ std::string address = "localhost";
+ int port = 4002;
+
+ UDPServer server = UDPServer(address, port);
+
+ std::size_t length{32768};
+ std::size_t lastIndex{0};
+
+ std::vector<unsigned short> buf(16000);
+
+ std::cout << "Receiving UDP packages: " << std::endl;
+
+// for(auto i = 0; i < 27; i++){
+// std::function<void(void)> f = [=]() {
+// server.recv();
+// };
+// start();
+// }
+
+ while(true){
+ int bytes = server.recv((char*)buf.data(), length);
+ std::size_t index = *((std::size_t *)buf.data());
+ if(index%1000 == 99) printf("%lu\n", index);
+
+ if(lastIndex != (index-1))
+ BOOST_LOG_TRIVIAL(warning) << "Packet loss or wrong order!";
+
+ lastIndex = index;
+
+ BOOST_LOG_TRIVIAL(debug) << "Server: Received " << bytes << " Bytes with Index " << index;
+ }
+
+ return 0;
+
+}